diff --git a/.gitignore b/.gitignore index 9ff6447..d638b75 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ project/auxillary/vis_ast/dependencies/temp test/gen/original singleheader/gen/scratch.hpp test/gen/scratch.cpp +gen_c_library/gen diff --git a/.vscode/bookmarks.json b/.vscode/bookmarks.json index 124083b..e69de29 100644 --- a/.vscode/bookmarks.json +++ b/.vscode/bookmarks.json @@ -1,14 +0,0 @@ -{ - "files": [ - { - "path": "project/auxillary/vis_ast/dependencies/temp/raylib-master/src/rcamera.h", - "bookmarks": [ - { - "line": 140, - "column": 14, - "label": "" - } - ] - } - ] -} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 6e9762e..576ec8d 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,9 +1,9 @@ { "configurations": [ { - "name": "Win32 msvc", + "name": "Bootstrap", "includePath": [ - "${workspaceFolder}/**" + "${workspaceFolder}/base/**" ], "defines": [ "_DEBUG", @@ -15,15 +15,44 @@ "GEN_INTELLISENSE_DIRECTIVES", "INTELLISENSE_DIRECTIVES" ], + "cStandard": "c11", + "cppStandard": "c++17", "windowsSdkVersion": "10.0.19041.0", "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe", "intelliSenseMode": "msvc-x64", - "compileCommands": "${workspaceFolder}/project/build/compile_commands.json" + "compileCommands": "${workspaceFolder}/.vscode/tasks.json", + "compilerArgs": [ + "/EHsc-", + "/GR-", + "/Zc:preprocessor", + "/FC" + ] + }, + { + "name": "Win32 msvc c_library", + "includePath": [ + "${workspaceFolder}/gen_c_library/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE", + "GEN_TIME", + "GEN_IMPLEMENTATION", + // "GEN_DONT_USE_NAMESPACE" + "GEN_INTELLISENSE_DIRECTIVES", + "INTELLISENSE_DIRECTIVES" + ], + "cppStandard": "c++17", + "windowsSdkVersion": "10.0.19041.0", + "compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.29.30133/bin/HostX64/x64/cl.exe", + "intelliSenseMode": "msvc-x64", + "compileCommands": "${workspaceFolder}/.vscode/tasks.json" }, { "name": "Win32 clang", "includePath": [ - "${workspaceFolder}/**" + "${workspaceFolder}/base/**" ], "defines": [ "_DEBUG", @@ -36,9 +65,9 @@ "INTELLISENSE_DIRECTIVES" ], "windowsSdkVersion": "10.0.19041.0", - "compilerPath": "C:/Users/Ed/scoop/apps/llvm/current/bin/clang++.exe", + "compilerPath": "clang++.exe", "intelliSenseMode": "windows-clang-x64", - "compileCommands": "${workspaceFolder}/project/build/compile_commands.json" + "compileCommands": "${workspaceFolder}/.vscode/tasks.json" } ], "version": 4 diff --git a/.vscode/launch.json b/.vscode/launch.json index 60fd398..3a6c660 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,39 +4,20 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug gentime lldb", - "program": "${workspaceFolder}/test/test.exe", - "args": [], - "cwd": "${workspaceFolder}/test/", - "postRunCommands": [ - ] - }, { "type": "cppvsdbg", "request": "launch", - "name": "Debug gentime vsdbg", - "program": "${workspaceFolder}/test/build/test.exe", + "name": "Debug base vsdbg", + "program": "${workspaceFolder}/base/build/base.exe", "args": [], - "cwd": "${workspaceFolder}/test/", - "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" - }, - { - "type": "cppvsdbg", - "request": "launch", - "name": "Debug bootstrap vsdbg", - "program": "${workspaceFolder}/project/build/bootstrap.exe", - "args": [], - "cwd": "${workspaceFolder}/project/", + "cwd": "${workspaceFolder}/base/", "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" }, { "type": "cppvsdbg", "request": "launch", "name": "Debug singleheader vsdbg", - "program": "${workspaceFolder}/singleheader/build/gencpp_singleheader.exe", + "program": "${workspaceFolder}/singleheader/build/singleheader.exe", "args": [], "cwd": "${workspaceFolder}/singleheader/", "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" @@ -49,24 +30,6 @@ "args": [], "cwd": "${workspaceFolder}/unreal_engine/", "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" - }, - { - "type": "cppvsdbg", - "request": "launch", - "name": "Debug raylib refactor vsdbg", - "program": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/raylib/build/raylib_refactor.exe", - "args": [], - "cwd": "${workspaceFolder}/project/auxillary/vis_ast/dependencies/temp/raylib-master/src/", - "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" - }, - { - "type": "cppvsdbg", - "request": "launch", - "name": "Debug VIS AST", - "program": "${workspaceFolder}/project/auxillary/vis_ast/binaries/vis_ast.exe", - "args": [], - "cwd": "${workspaceFolder}/project/auxillary/vis_ast/binaries/", - "visualizerFile": "${workspaceFolder}/scripts/gencpp.natvis" } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 6e65a84..f3a91f7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,7 +37,26 @@ "propidl.h": "c", "android_native_app_glue.h": "c", "raylib.h": "c", - "*.m": "cpp" + "*.m": "cpp", + "atomic": "cpp", + "gen.h": "c", + "string_ops.hpp": "c", + "assert.h": "c", + "intrin.h": "c", + "bit": "cpp", + "cmath": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "iosfwd": "cpp", + "new": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "xstddef": "cpp" }, "C_Cpp.intelliSenseEngineFallback": "disabled", "mesonbuild.configureOnOpen": true, @@ -48,8 +67,10 @@ "C_Cpp.files.exclude": { "**/.vscode": true, "**/.vs": true, - "**/sanity.gen.hpp": true + "**/sanity.gen.hpp": true, + "test/**":true, }, "autoHide.autoHidePanel": false, - "autoHide.autoHideSideBar": false + "autoHide.autoHideSideBar": false, + "dimmer.enabled": false } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..c54587d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,144 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build Bootstrap", + "type": "shell", + "command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + "args": [ + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/scripts/build.ci.ps1", + "bootstrap", + "msvc" + ], + "group": "build", + "problemMatcher": { + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(warning|error)\\s*(\\w+)\\s*:\\s*(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "code": 4, + "message": 5 + } + }, + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": true + } + }, + { + "label": "Build C Library", + "type": "shell", + "command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + "args": [ + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/scripts/build.ci.ps1", + "c_library", + "msvc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": { + "owner": "cpp", + "fileLocation": [ + "relative", + "${workspaceFolder}" + ], + "pattern": { + "regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(warning|error)\\s*(\\w+)\\s*:\\s*(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "code": 4, + "message": 5 + } + }, + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": true + } + }, + { + "label": "Build Singleheader (MSVC)", + "type": "shell", + "command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + "args": [ + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/scripts/build.ci.ps1", + "singleheader", + "msvc", + "debug" + ], + "group": "build", + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceFolder}"], + "pattern": [ + { + "regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(error|warning|info|note)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "code": 4, + "message": 5 + } + ] + }, + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": true + } + }, + { + "label": "Build Unreal (MSVC)", + "type": "shell", + "command": "C:\\Program Files\\PowerShell\\7\\pwsh.exe", + "args": [ + "-ExecutionPolicy", + "Bypass", + "-File", + "${workspaceFolder}/scripts/build.ci.ps1", + "unreal", + "msvc", + "debug" + ], + "group": "build", + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceFolder}"], + "pattern": [ + { + "regexp": "^(.*)\\((\\d+)\\)\\s*:\\s*(error|warning|info|note)\\s+(\\w{1,2}\\d+)\\s*:\\s*(.*)$", + "file": 1, + "line": 2, + "severity": 3, + "code": 4, + "message": 5 + } + ] + }, + "presentation": { + "reveal": "always", + "panel": "shared", + "clear": true + } + } + ] +} diff --git a/Readme.md b/Readme.md index 20d84fd..98c05c0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,16 +1,29 @@ # gencpp -An attempt at simple staged metaprogramming for c/c++. +An attempt at simple staged metaprogramming for C/C++. -The library API is a composition of code element constructors. -These build up a code AST to then serialize with a file builder. +The library API is a composition of code element constructors, and a non-standards-compliant single-pass C/C++ parser. +These build up a code AST to then serialize with a file builder, or can be traversed for staged-reflection of C/C++ code. -This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto). -Its not meant to be a black box metaprogramming utility, it should be easy to intergrate into a user's project domain. +This code base attempts follow the [handmade philosophy](https://handmade.network/manifesto). +Its not meant to be a black box metaprogramming utility, it should be easy to intergrate into a user's project domain. + +## Documentation + +* [docs - General](./docs/Readme.md): Overview and additional docs + * [AST_Design](./docs/AST_Design.md): Overvie of ASTs + * [AST Types](./docs/AST_Types.md): Listing of all AST types along with their Code type interface. + * [Parsing](./docs/Parsing.md): Overview of the parsing interface. + * [Parser Algo](./docs/Parser_Algo.md): In-depth breakdown of the parser's implementation. +* [base](./base/Readme.md): Essential (base) library. +* [gen_c_library](./gen_c_library/): C11 library variant generation (single header and segmeented). +* [gen_segmented](./gen_segmented/): Segemented C++ (`gen.`, `gen.dep.`) generation +* [gen_singleheader](./gen_singleheader/): Singlehader C++ generation `gen.hpp` +* [gen_unreal_engine](./gen_unreal_engine/): Unreal Engine thirdparty code generation. ## Notes -**On Partial Hiatus: Life has got me tackling other issues..** +**On Partial Hiatus: Life has got me tackling other issues..** I will be passively updating the library with bug fixes and minor improvements as I use it for my personal projects. There won't be any major reworks or features to this thing for a while. @@ -21,17 +34,13 @@ The library can already be used to generate code just fine, but the parser is wh A `natvis` and `natstepfilter` are provided in the scripts directory (its outdated, I'll update this readme when its not). -***The editor and scanner have not been implemented yet. The scanner will come first, then the editor.*** - -A C variant is hosted [here](https://github.com/Ed94/genc); I will complete it when this library is feature complete, it should be easier to make than this... - ## Usage A metaprogram is built to generate files before the main program is built. We'll term runtime for this program as `GEN_TIME`. The metaprogram's core implementation are within `gen.hpp` and `gen.cpp` in the project directory. `gen.cpp` \`s `main()` is defined as `gen_main()` which the user will have to define once for their program. There they will dictate everything that should be generated. -In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't required at all): +In order to keep the locality of this code within the same files the following pattern may be used (although this pattern isn't the best to use): Within `program.cpp` : @@ -54,7 +63,6 @@ u32 gen_main() // Regular runtime dependent on the generated code here. #endif - ``` The design uses a constructive builder API for the code to generate. @@ -115,7 +123,7 @@ Code header = code_str( `name` is a helper macro for providing a string literal with its size, intended for the name parameter of functions. `code` is a helper macro for providing a string literal with its size, but intended for code string parameters. -`args` is a helper macro for providing the number of arguments to varadic constructors. +`args` is a helper macro for providing the number of arguments to varadic constructors. `code_str` is a helper macro for writting `untyped_str( code( ))` All three constrcuton interfaces will generate the following C code: @@ -129,7 +137,7 @@ struct ArrayHeader }; ``` -**Note: The formatting shown here is not how it will look. For your desired formatting its recommended to run a pass through the files with an auto-formatter.** +**Note: The formatting shown here is not how it will look. For your desired formatting its recommended to run a pass through the files with an auto-formatter.** *(The library currently uses clang-format for formatting, beware its pretty slow...)* ## Building diff --git a/base/Readme.md b/base/Readme.md new file mode 100644 index 0000000..4f25e5a --- /dev/null +++ b/base/Readme.md @@ -0,0 +1,156 @@ +## Navigation + +# base + +[Top](../Readme.md) + +* [docs](../docs/Readme.md) + +The library is fragmented into a series of headers and source files meant to be scanned in and then generated to a standard target format, or a user's desires. + +Standard formats: + +* **base**: Files are in granular pieces separated into four directories: + * **dependencies**: Originally from the c-zpl library and modified thereafter. + * **components**: The essential definitions of the library. + * **helpers**: Contains helper functionality used by base and other libraries to regenerate or generate the other library formats. + * `base_codegen.hpp`: Helps with self-hosted code generation of enums, and operator overload inlines of the code types. + * `..inline.`: macros that are meant to be injected at specific locations of the library. + * `misc.hpp`: Misc functionality used by the library generation metaprograms. + * `undef.macros.h`: Undefines all macros from library that original were intended to leak into user code. + * **auxillary**: Non-essential tooling: + * `Builder`: Similar conceptually to Jai programming language's *builder*, just opens a file and prepares a string buffer to serialize code into (`builder_print`, `builder_print_fmt`). Then write & close the file when completed (`builder_write`). + * **`Scanner`**: Interface to load up `Code` from files two basic funcctions are currently provided. + * `scan_file`: Used mainly by the library format generators to directly scan files into untyped `Code` (raw string content, pre-formatted no AST parsed). + * `parse_file`: Used to read file and then parsed to populate a `CodeBody` AST. + * CSV parsing via one or two columns simplified. +* **gen_segemetned**: Dependencies go into gen.dep.{hpp/cpp} and components into gen.{hpp/cpp} +* **gen_singleheader**: Everything into a single file: gen.hpp +* **gen_unreal_engine**: Like gen_segemented but the library is modified slightly to compile as a thirdparty library within an Unreal Engine plugin or module. +* **gen_c_library**: The library is heavily modifed into C11 compliant code. A segemented and single-header set of variants are generatd. + +Code not making up the core library is located in `auxiliary/.`. These are optional extensions or tools for the library. + +## Dependencies + +The project has no external dependencies beyond: + +* `errno.h` +* `stat.h` +* `stdarg.h` +* `stddef.h` +* `stdio.h` +* `copyfile.h` (Mac) +* `types.h` (Linux) +* `sys/man.h` (Linux) +* `fcntl.h` (POSXIX Filesystem) +* `unistd.h` (Linux/Mac) +* `intrin.h` (Windows) +* `io.h` (Windows with gcc) +* `windows.h` (Windows) + +Dependencies for the project are wrapped within `GENCPP_ROLL_OWN_DEPENDENCIES` (Defining it will disable them). +The majority of the dependency's implementation was derived from the [c-zpl library](https://github.com/zpl-c/zpl). + +See the following files for any updates: + +* [`platform.hpp`](./dependencies/platform.hpp) +* [`src_start.cpp`](./dependencies/src_start.cpp) +* [`filesystem.cpp`](./dependencies/filesystem.cpp) +* [`memory.cpp`](./dependencies/memory.cpp) + +## Conventions + +This library was written in a subset of C++ where the following are not used at all: + +* RAII (Constructors/Destructors), lifetimes are managed using named static or regular functions. +* Language provide dynamic dispatch, RTTI +* Object-Oriented Inheritance +* Exceptions + +Polymorphic & Member-functions are used as an ergonomic choice, along with a conserative use of operator overloads. +The base library itself does not use anything but C-like features to allow for generating a derviative compatiable with C. + +Member function support or free-functions with reference object passing are wrapped in `! GEN_C_LIKE CPP` preprocess conditionals. + + + +## C++ template usage + +There are only 4 template definitions in the entire library (C++ versions). (`Array`, `Hashtable`, `swap`, and `tmpl_cast(CodeT code)`) + +Two generic templated containers are used throughout the library: + +* `template< class Type> struct Array` +* `template< class Type> struct HashTable` + +`tmpl_cast(CodeT code)` is just an alternative way to explicitly cast to code. Its usage is wrapped in a macro called `cast` for the base library (needed for interoperability with C). + +`template< class Type> swap( Type& a, Type& b)` is used over a macro. + +Otherwise the library is free of any templates. + +## Macro usage + +Since this is a meta-programming library, it was desired to keep both templates and macros (especially macros) usage very limited. + +Most macros are defined within [macros.hpp](./dependencies/macros.hpp). + +The most advanced macro usage is `num_args` which is a helper for counting the number of arguments of another macro. + +Any large macros used implementing the gen interface or parser are going to be phased out in favor of just forcinlined functions. +*(Unless there is a hot-path that requires them)* + +The vast majority of macros should be single-line subsitutions that either add: + +* Improvements to searching +* Inteniality of keyword usage +* A feature that only the preprocessor has (ex: function name reflection or stringifying) +* Compatibility of statements or expressions bewteen C & C++ that cannot be parsed by gencpp itself. +* Masking highly verbose syntax (the latter is getting phased out). + +[gen_c_library](../gen_c_library/) has the most advanced set of macros for c11's generic selection. + +* A significant amount of explicit code geneeration is utilized to keep abuse of the preprocessor to the absolute minimum. +* There is a heavy set of documentation inlined wth them; their naming is also highly verbose and explicit. +* See its documentation for more information. + +## On base code generation + +There are ***five*** header files which are automatically generated using [base_codegen.hpp](./helpers/base_codegen.hpp) by [base.cpp](./base.cpp). They are all located in [components/gen](./components/gen/). + +* [`ecodetypes.hpp`](./components/gen/ecode.hpp): `CodeType` enum definition and related implementaiton. Generation is based off of [`ECodeType.csv](./enums/ECodeTypes.csv). +* [`especifier.hpp`](./components/gen/especifier.hpp): `Specifier` enum definition, etc. Generated using [`ESpecifier.csv`](./enums/ESpecifier.csv). +* [`eoperator.hpp`](./components/gen/eoperator.hpp): `Operator` enum definition, etc. Generated using [`EOperator.hpp`](./enums/EOperator.csv). +* [`etoktype.cpp`](./components/gen/etoktype.cpp): `TokType` enum defininition, etc. Used by the lexer and parser backend. Uses two csvs: + * [`ETokType.csv`](./enums/ETokType.csv): Provides the enum entries and their strinng ids. + * [`AttributeTokens.csv`](./enums/AttributeTokens.csv): Provides tokens entries that should be considered as attributes by the lexer and parser. Sspecfiically macro attributes such as those use for exporting symbols. +* [`ast_inlines.hpp`](./components/gen/ast_inlines.hpp): Member trivial `operator` definitions for C++ code types. Does not use a csv. + +[`misc.hpp`](./helpers/misc.hpp): Has shared functions used by the library generation meta-programs throughout this codebase. + +## On multi-threading + +Currently unsupported. I want the library to be *stable* and *correct*, with the addition of exhausting all basic single-threaded optimizations before I consider multi-threading. + +## Extending the library + +This library is relatively very small (for parsing C++), and can be extended without much hassle. + +The convention you'll see used throughout the upfront interface of the library is as follows: + +1. Check name or parameters to make sure they are valid for the construction requested +2. Create a code object using `make_code`. +3. Populate immediate fields (Name, Type, ModuleFlags, etc) +4. Populate sub-entires using `add_entry`. If using the default serialization function `to_string`, follow the order at which entires are expected to appear (there is a strong ordering expected). + +Names or Content fields are interned strings and thus showed be cached using `get_cached_string` if its desired to preserve that behavior. + +`def_operator` is the most sophisticated upfront constructor as it has multiple permutations of definitions that could be created that are not trivial to determine if valid. + +The parser is documented under [`docs/Parsing.md`](../docs/Parsing.md) and [`docs/Parser_Algo.md`](../docs/Parser_Algo.md). Extending it is more serious. + +## A note on compilation and runtime generation speed + +The library is designed to be fast to compile and generate code at runtime as fast as resonable possible on a debug build. +Its recommended that your metaprogam be compiled using a single translation unit (unity build). diff --git a/base/auxillary/builder.cpp b/base/auxillary/builder.cpp new file mode 100644 index 0000000..eb5e931 --- /dev/null +++ b/base/auxillary/builder.cpp @@ -0,0 +1,59 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +# include "builder.hpp" +#endif + +#pragma region Builder + +Builder builder_open( char const* path ) +{ + Builder result; + + FileError error = file_open_mode( & result.File, EFileMode_WRITE, path ); + if ( error != EFileError_NONE ) + { + log_failure( "gen::File::open - Could not open file: %s", path); + return result; + } + + result.Buffer = string_make_reserve( GlobalAllocator, Builder_StrBufferReserve ); + + // log_fmt("$Builder - Opened file: %s\n", result.File.filename ); + return result; +} + +void builder_pad_lines( Builder* builder, s32 num ) +{ + string_append_strc( & builder->Buffer, txt("\n") ); +} + +void builder_print( Builder* builder, Code code ) +{ + String str = code_to_string(code); + // const ssize len = str.length(); + // log_fmt( "%s - print: %.*s\n", File.filename, len > 80 ? 80 : len, str.Data ); + string_append_string( & builder->Buffer, str ); +} + +void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ) +{ + ssize res; + char buf[ GEN_PRINTF_MAXLEN ] = { 0 }; + + res = str_fmt_va( buf, count_of( buf ) - 1, fmt, va ) - 1; + + string_append_c_str_len( (String*) & (builder->Buffer), (char const*)buf, res); +} + +void builder_write(Builder* builder) +{ + b32 result = file_write( & builder->File, builder->Buffer, string_length(builder->Buffer) ); + + if ( result == false ) + log_failure("gen::File::write - Failed to write to file: %s\n", file_name( & builder->File ) ); + + log_fmt( "Generated: %s\n", builder->File.filename ); + file_close( & builder->File ); + string_free(& builder->Buffer); +} + +#pragma endregion Builder diff --git a/base/auxillary/builder.hpp b/base/auxillary/builder.hpp new file mode 100644 index 0000000..3c37fba --- /dev/null +++ b/base/auxillary/builder.hpp @@ -0,0 +1,70 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +# pragma once +# include "helpers/push_ignores.inline.hpp" +# include "components/header_start.hpp" +# include "components/types.hpp" +# include "components/gen/ecode.hpp" +# include "components/gen/eoperator.hpp" +# include "components/gen/especifier.hpp" +# include "components/ast.hpp" +# include "components/code_types.hpp" +# include "components/ast_types.hpp" +# include "components/interface.hpp" +# include "components/inlines.hpp" +# include "components/gen/ast_inlines.hpp" +# include "components/header_end.hpp" +using namespace gen; +#endif + +#pragma region Builder + +struct Builder; +typedef struct Builder Builder; + +Builder builder_open ( char const* path ); +void builder_pad_lines ( Builder* builder, s32 num ); +void builder_print ( Builder* builder, Code code ); +void builder_print_fmt_va( Builder* builder, char const* fmt, va_list va ); +void builder_print_fmt ( Builder* builder, char const* fmt, ... ) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( builder, fmt, va ); + va_end( va ); +} +void builder_write( Builder* builder ); + +struct Builder +{ + FileInfo File; + String Buffer; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP + forceinline static Builder open( char const* path ) { return builder_open(path); } + + forceinline void pad_lines( s32 num ) { return builder_pad_lines(this, num); } + + forceinline void print( Code code ) { return builder_print(this, code); } + forceinline void print_fmt( char const* fmt, ... ) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( this, fmt, va ); + va_end( va ); + } + + forceinline void write() { return builder_write(this); } +#endif +}; + +#if GEN_COMPILER_CPP && ! GEN_C_LIKE_CPP +void builder_pad_lines( Builder& builder, s32 num ) { return builder_pad_lines(& builder, num); } +void builder_print ( Builder& builder, Code code ) { return builder_print(& builder, code); } +void builder_write ( Builder& builder ) { return builder_write(& builder ); } +void builder_print_fmt( Builder& builder, char const* fmt, ...) { + va_list va; + va_start( va, fmt ); + builder_print_fmt_va( & builder, fmt, va ); + va_end( va ); +} +#endif + +#pragma endregion Builder diff --git a/base/auxillary/gen_template.hpp b/base/auxillary/gen_template.hpp new file mode 100644 index 0000000..101f7de --- /dev/null +++ b/base/auxillary/gen_template.hpp @@ -0,0 +1,35 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +# pragma once +# include "helpers/push_ignores.inline.hpp" +# include "components/header_start.hpp" +# include "components/types.hpp" +# include "components/gen/ecode.hpp" +# include "components/gen/eoperator.hpp" +# include "components/gen/especifier.hpp" +# include "components/ast.hpp" +# include "components/code_types.hpp" +# include "components/ast_types.hpp" +# include "components/interface.hpp" +# include "components/inlines.hpp" +# include "components/gen/ast_inlines.hpp" +# include "components/header_end.hpp" +#endif + +/* + Explicitly generates a resolved definition of a cpp template definition. + + TODO(Ed): Needs implementing for the C-library variant. + TODO(Ed): We need a non syntax subst implemtnation for Strings for this to work. It must subst keywords directly based on template parameter names. + + This is only meant to be used on relatively trivial templates, where the type or numeric is mostly a 'duck' type. + It cannot parse complex template parameters. + + The varadic args should correspond 1:1 with the type of objects the generator expects from the template's parameters.alignas. +*/ + +CodeOperator gen_operator_template( CodeTemplate template, ... ); +CodeFn gen_func_template( CodeTemplate template, ... ); +Code gen_class_struct_template( CodeTemplate template, ... ); + +Code gen_template( CodeTemplate template, ... ); +Code gen_template( StrC template, StrC instantiation ); diff --git a/project/auxillary/scanner.hpp b/base/auxillary/scanner.cpp similarity index 54% rename from project/auxillary/scanner.hpp rename to base/auxillary/scanner.cpp index 97af098..70b12f3 100644 --- a/project/auxillary/scanner.hpp +++ b/base/auxillary/scanner.cpp @@ -1,12 +1,9 @@ #ifdef GEN_INTELLISENSE_DIRECTIVES -# pragma once -# include "gen.hpp" +# include "scanner.hpp" #endif -// This is a simple file reader that reads the entire file into memory. -// It has an extra option to skip the first few lines for undesired includes. -// This is done so that includes can be kept in dependency and component files so that intellisense works. -inline +#pragma region Scanner + Code scan_file( char const* path ) { FileInfo file; @@ -23,9 +20,9 @@ Code scan_file( char const* path ) GEN_FATAL("scan_file: %s is empty", path ); } - String str = String::make_reserve( GlobalAllocator, fsize ); + String str = string_make_reserve( GlobalAllocator, fsize ); file_read( & file, str, fsize ); - str.get_header().Length = fsize; + string_get_header(str)->Length = fsize; // Skip GEN_INTELLISENSE_DIRECTIVES preprocessor blocks // Its designed so that the directive should be the first thing in the file. @@ -39,7 +36,7 @@ Code scan_file( char const* path ) const StrC def_intellisense = txt("GEN_INTELLISENSE_DIRECTIVES" ); bool found_directive = false; - char const* scanner = str.Data; + char const* scanner = (char const*)str; s32 left = fsize; while ( left ) { @@ -52,7 +49,7 @@ Code scan_file( char const* path ) if ( ! found_directive ) { - if ( left && str_compare( scanner, directive_start.Ptr, directive_start.Len ) == matched ) + if ( left && str_compare_len( scanner, directive_start.Ptr, directive_start.Len ) == matched ) { scanner += directive_start.Len; left -= directive_start.Len; @@ -60,7 +57,7 @@ Code scan_file( char const* path ) while ( left && char_is_space( current ) ) move_fwd(); - if ( left && str_compare( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) + if ( left && str_compare_len( scanner, def_intellisense.Ptr, def_intellisense.Len ) == matched ) { scanner += def_intellisense.Len; left -= def_intellisense.Len; @@ -80,7 +77,7 @@ Code scan_file( char const* path ) continue; } - if ( left && str_compare( scanner, directive_end.Ptr, directive_end.Len ) == matched ) + if ( left && str_compare_len( scanner, directive_end.Ptr, directive_end.Len ) == matched ) { scanner += directive_end.Len; left -= directive_end.Len; @@ -94,19 +91,18 @@ Code scan_file( char const* path ) move_fwd(); // sptr skip_size = fsize - left; - if ( (scanner + 2) >= ( str.Data + fsize ) ) + if ( (scanner + 2) >= ( (char const*) str + fsize ) ) { mem_move( str, scanner, left ); - str.get_header().Length = left; + string_get_header(str)->Length = left; break; } mem_move( str, scanner, left ); - str.get_header().Length = left; + string_get_header(str)->Length = left; break; } - } move_fwd(); @@ -117,44 +113,36 @@ Code scan_file( char const* path ) } file_close( & file ); - return untyped_str( str ); + return untyped_str( string_to_strc(str) ); } -#if 0 -struct CodeFile -{ - using namespace Parser; - - String FilePath; - TokArray Tokens; - Array ParseFailures; - Code CodeRoot; -}; - -namespace Parser -{ - struct ParseFailure - { - String Reason; - Code Node; - }; +CodeBody parse_file( const char* path ) { + FileContents file = file_read_contents( GlobalAllocator, true, path ); + StrC content = { file.size, (char const*)file.data }; + CodeBody code = parse_global_body( content ); + log_fmt("\nParsed: %s\n", path); + return code; } -CodeFile scan_file( char const* path ) -{ - using namespace Parser; - - CodeFile - result = {}; - result.FilePath = String::make( GlobalAllocator, path ); - - Code code = scan_file( path ); - result.CodeRoot = code; - - ParseContext context = parser_get_last_context(); - result.Tokens = context.Tokens; - result.ParseFailures = context.Failures; +CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path) { + FileContents content = file_read_contents( allocator, file_zero_terminate, path ); + Arena csv_arena = arena_init_from_memory(content.data, content.size); + CSV_Column result; + csv_parse( & result.ADT, rcast(char*, content.data), allocator, false ); + result.Content = result.ADT.nodes[0].nodes; return result; } -#endif + +CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path) { + FileContents content = file_read_contents( allocator, file_zero_terminate, path ); + Arena csv_arena = arena_init_from_memory(content.data, content.size); + + CSV_Columns2 result; + csv_parse( & result.ADT, rcast(char*, content.data), allocator, false ); + result.Col_1 = result.ADT.nodes[0].nodes; + result.Col_2 = result.ADT.nodes[1].nodes; + return result; +} + +#pragma endregion Scanner diff --git a/base/auxillary/scanner.hpp b/base/auxillary/scanner.hpp new file mode 100644 index 0000000..12cc4d3 --- /dev/null +++ b/base/auxillary/scanner.hpp @@ -0,0 +1,46 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +# pragma once +# include "helpers/push_ignores.inline.hpp" +# include "components/header_start.hpp" +# include "components/types.hpp" +# include "components/gen/ecode.hpp" +# include "components/gen/eoperator.hpp" +# include "components/gen/especifier.hpp" +# include "components/ast.hpp" +# include "components/code_types.hpp" +# include "components/ast_types.hpp" +# include "components/interface.hpp" +# include "components/inlines.hpp" +# include "components/gen/ast_inlines.hpp" +# include "components/header_end.hpp" +#endif + +#pragma region Scanner + +// This is a simple file reader that reads the entire file into memory. +// It has an extra option to skip the first few lines for undesired includes. +// This is done so that includes can be kept in dependency and component files so that intellisense works. +Code scan_file( char const* path ); + +CodeBody parse_file( const char* path ); + +// The follow is basic support for light csv parsing (use it as an example) +// Make something robust if its more serious. + +typedef struct CSV_Column CSV_Column; +struct CSV_Column { + CSV_Object ADT; + Array(ADT_Node) Content; +}; + +typedef struct CSV_Columns2 CSV_Columns2; +struct CSV_Columns2 { + CSV_Object ADT; + Array(ADT_Node) Col_1; + Array(ADT_Node) Col_2; +}; + +CSV_Column parse_csv_one_column(AllocatorInfo allocator, char const* path); +CSV_Columns2 parse_csv_two_columns(AllocatorInfo allocator, char const* path); + +#pragma endregion Scanner diff --git a/base/base.cpp b/base/base.cpp new file mode 100644 index 0000000..e1d5c1a --- /dev/null +++ b/base/base.cpp @@ -0,0 +1,68 @@ +#define GEN_DEFINE_LIBRARY_CODE_CONSTANTS +#define GEN_ENFORCE_STRONG_CODE_TYPES +#define GEN_EXPOSE_BACKEND +#define GEN_C_LIKE_CPP 1 +#include "gen.cpp" +#include "helpers/push_ignores.inline.hpp" + +#include + +GEN_NS_BEGIN +#include "helpers/base_codegen.hpp" +#include "helpers/misc.hpp" +GEN_NS_END + +using namespace gen; + +constexpr char const* path_format_style = "../scripts/.clang-format"; +constexpr char const* scratch_file = "build/scratch.hpp"; + +Code format( Code code ) { + return code_refactor_and_format(code, scratch_file, nullptr, path_format_style ); +} + +constexpr char const* generation_notice = +"// This file was generated automatially by gencpp's bootstrap.cpp " +"(See: https://github.com/Ed94/gencpp)\n\n"; + +int gen_main() +{ + gen::init(); + + CodeBody gen_component_header = def_global_body( args( + def_preprocess_cond( PreprocessCond_IfDef, txt("GEN_INTELLISENSE_DIRECTIVES") ), + pragma_once, + def_include(txt("components/types.hpp")), + preprocess_endif, + fmt_newline, + untyped_str( to_strc_from_c_str(generation_notice) ) + )); + + CodeBody ecode = gen_ecode ( "enums/ECodeTypes.csv" ); + CodeBody eoperator = gen_eoperator ( "enums/EOperator.csv" ); + CodeBody especifier = gen_especifier( "enums/ESpecifier.csv" ); + CodeBody ast_inlines = gen_ast_inlines(); + + Builder header_ecode = builder_open( "components/gen/ecodetypes.hpp" ); + builder_print( & header_ecode, gen_component_header ); + builder_print( & header_ecode, format(ecode) ); + builder_write( & header_ecode); + + Builder header_eoperator = builder_open( "components/gen/eoperator.hpp" ); + builder_print( & header_eoperator, gen_component_header ); + builder_print( & header_eoperator, format(eoperator) ); + builder_write( & header_eoperator ); + + Builder header_especifier = builder_open( "components/gen/especifier.hpp" ); + builder_print( & header_especifier, gen_component_header ); + builder_print( & header_especifier, format(especifier) ); + builder_write( & header_especifier); + + Builder header_ast_inlines = builder_open( "components/gen/ast_inlines.hpp" ); + builder_print( & header_ast_inlines, gen_component_header ); + builder_print( & header_ast_inlines, format(ast_inlines) ); + builder_write( & header_ast_inlines); + + gen::deinit(); + return 0; +} diff --git a/base/components/ast.cpp b/base/components/ast.cpp new file mode 100644 index 0000000..b0b9347 --- /dev/null +++ b/base/components/ast.cpp @@ -0,0 +1,1277 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "static_data.cpp" +#endif + +global Code Code_Global; +global Code Code_Invalid; + +// This serializes all the data-members in a "debug" format, where each member is printed with its associated value. +StrC code_debug_str(Code self) +{ + GEN_ASSERT(self != nullptr); + String result_stack = string_make_reserve( GlobalAllocator, kilobytes(1) ); + String* result = & result_stack; + + if ( self->Parent ) + string_append_fmt( result, "\n\tParent : %SC %SC", code_type_str(self->Parent), self->Name.Len ? self->Name : txt("Null") ); + else + string_append_fmt( result, "\n\tParent : %SC", txt("Null") ); + + string_append_fmt( result, "\n\tName : %SC", self->Name.Len ? self->Name : txt("Null") ); + string_append_fmt( result, "\n\tType : %SC", code_type_str(self) ); + string_append_fmt( result, "\n\tModule Flags : %SC", module_flag_to_str( self->ModuleFlags ) ); + + switch ( self->Type ) + { + case CT_Invalid: + case CT_NewLine: + case CT_Access_Private: + case CT_Access_Protected: + case CT_Access_Public: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + break; + + case CT_Untyped: + case CT_Execution: + case CT_Comment: + case CT_PlatformAttributes: + case CT_Preprocess_Define: + case CT_Preprocess_Include: + case CT_Preprocess_Pragma: + case CT_Preprocess_If: + case CT_Preprocess_ElIf: + case CT_Preprocess_Else: + case CT_Preprocess_IfDef: + case CT_Preprocess_IfNotDef: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tContent: %SC", self->Content ); + break; + + case CT_Class: + case CT_Struct: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tParentAccess: %SC", self->ParentType ? access_spec_to_str( self->ParentAccess ) : txt("No Parent") ); + string_append_fmt( result, "\n\tParentType : %SC", self->ParentType ? code_type_str(self->ParentType) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Class_Fwd: + case CT_Struct_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tParentAccess: %SC", self->ParentType ? access_spec_to_str( self->ParentAccess ) : txt("No Parent") ); + string_append_fmt( result, "\n\tParentType : %SC", self->ParentType ? code_type_str(self->ParentType) : txt("Null") ); + break; + + case CT_Constructor: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs) ) : txt("Null") ); + string_append_fmt( result, "\n\tInitializerList: %SC", self->InitializerList ? string_to_strc( code_to_string(self->InitializerList) ) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params) ) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Constructor_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs) ) : txt("Null") ); + string_append_fmt( result, "\n\tInitializerList: %SC", self->InitializerList ? string_to_strc( code_to_string(self->InitializerList) ) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params) ) : txt("Null") ); + break; + + case CT_Destructor: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs) ) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Destructor_Fwd: + break; + + case CT_Enum: + case CT_Enum_Class: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tUnderlying Type : %SC", self->UnderlyingType ? string_to_strc( code_to_string(self->UnderlyingType)) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Enum_Fwd: + case CT_Enum_Class_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tUnderlying Type : %SC", self->UnderlyingType ? string_to_strc( code_to_string(self->UnderlyingType)) : txt("Null") ); + break; + + case CT_Extern_Linkage: + case CT_Namespace: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tBody: %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Friend: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tDeclaration: %SC", self->Declaration ? string_to_strc( code_to_string(self->Declaration)) : txt("Null") ); + break; + + case CT_Function: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes: %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tReturnType: %SC", self->ReturnType ? string_to_strc( code_to_string(self->ReturnType)) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params)) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Function_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes: %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tReturnType: %SC", self->ReturnType ? string_to_strc( code_to_string(self->ReturnType)) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params)) : txt("Null") ); + break; + + case CT_Module: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + break; + + case CT_Operator: + case CT_Operator_Member: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes: %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tReturnType: %SC", self->ReturnType ? string_to_strc( code_to_string(self->ReturnType)) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params)) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + string_append_fmt( result, "\n\tOp : %SC", operator_to_str( self->Op ) ); + break; + + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes: %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs) ) : txt("Null") ); + string_append_fmt( result, "\n\tReturnType: %SC", self->ReturnType ? string_to_strc( code_to_string(self->ReturnType) ) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params) ) : txt("Null") ); + string_append_fmt( result, "\n\tOp : %SC", operator_to_str( self->Op ) ); + break; + + case CT_Operator_Cast: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tValueType : %SC", self->ValueType ? string_to_strc( code_to_string(self->ValueType)) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Operator_Cast_Fwd: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tValueType : %SC", self->ValueType ? string_to_strc( code_to_string(self->ValueType)) : txt("Null") ); + break; + + case CT_Parameters: + string_append_fmt( result, "\n\tNumEntries: %d", self->NumEntries ); + string_append_fmt( result, "\n\tLast : %SC", self->Last->Name ); + string_append_fmt( result, "\n\tNext : %SC", self->Next->Name ); + string_append_fmt( result, "\n\tValueType : %SC", self->ValueType ? string_to_strc( code_to_string(self->ValueType)) : txt("Null") ); + string_append_fmt( result, "\n\tValue : %SC", self->Value ? string_to_strc( code_to_string(self->Value)) : txt("Null") ); + break; + + case CT_Specifiers: + { + string_append_fmt( result, "\n\tNumEntries: %d", self->NumEntries ); + string_append_strc( result, txt("\n\tArrSpecs: ") ); + + s32 idx = 0; + s32 left = self->NumEntries; + while ( left-- ) + { + StrC spec = spec_to_str( self->ArrSpecs[idx] ); + string_append_fmt( result, "%.*s, ", spec.Len, spec.Ptr ); + idx++; + } + string_append_fmt( result, "\n\tNextSpecs: %SC", self->NextSpecs ? code_debug_str(self->NextSpecs) : txt("Null") ); + } + break; + + case CT_Template: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params)) : txt("Null") ); + string_append_fmt( result, "\n\tDeclaration: %SC", self->Declaration ? string_to_strc( code_to_string(self->Declaration)) : txt("Null") ); + break; + + case CT_Typedef: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tUnderlyingType: %SC", self->UnderlyingType ? string_to_strc( code_to_string(self->UnderlyingType)) : txt("Null") ); + break; + + case CT_Typename: + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tReturnType : %SC", self->ReturnType ? string_to_strc( code_to_string(self->ReturnType)) : txt("Null") ); + string_append_fmt( result, "\n\tParams : %SC", self->Params ? string_to_strc( code_to_string(self->Params)) : txt("Null") ); + string_append_fmt( result, "\n\tArrExpr : %SC", self->ArrExpr ? string_to_strc( code_to_string(self->ArrExpr)) : txt("Null") ); + break; + + case CT_Union: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tAttributes: %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tBody : %SC", self->Body ? code_debug_str(self->Body) : txt("Null") ); + break; + + case CT_Using: + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tUnderlyingType: %SC", self->UnderlyingType ? string_to_strc( code_to_string(self->UnderlyingType)) : txt("Null") ); + break; + + case CT_Variable: + + if ( self->Parent && self->Parent->Type == CT_Variable ) + { + // Its a NextVar + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tValue : %SC", self->Value ? string_to_strc( code_to_string(self->Value)) : txt("Null") ); + string_append_fmt( result, "\n\tBitfieldSize: %SC", self->BitfieldSize ? string_to_strc( code_to_string(self->BitfieldSize)) : txt("Null") ); + string_append_fmt( result, "\n\tNextVar : %SC", self->NextVar ? code_debug_str(self->NextVar) : txt("Null") ); + break; + } + + if ( self->Prev ) + string_append_fmt( result, "\n\tPrev: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + if ( self->Next ) + string_append_fmt( result, "\n\tNext: %SC %SC", code_type_str(self->Prev), self->Prev->Name.Len ? self->Prev->Name : txt("Null") ); + + string_append_fmt( result, "\n\tInlineCmt : %SC", self->InlineCmt ? self->InlineCmt->Content : txt("Null") ); + string_append_fmt( result, "\n\tAttributes : %SC", self->Attributes ? string_to_strc( code_to_string(self->Attributes) ) : txt("Null") ); + string_append_fmt( result, "\n\tSpecs : %SC", self->Specs ? string_to_strc( code_to_string(self->Specs)) : txt("Null") ); + string_append_fmt( result, "\n\tValueType : %SC", self->ValueType ? string_to_strc( code_to_string(self->ValueType)) : txt("Null") ); + string_append_fmt( result, "\n\tBitfieldSize: %SC", self->BitfieldSize ? string_to_strc( code_to_string(self->BitfieldSize)) : txt("Null") ); + string_append_fmt( result, "\n\tValue : %SC", self->Value ? string_to_strc( code_to_string(self->Value)) : txt("Null") ); + string_append_fmt( result, "\n\tNextVar : %SC", self->NextVar ? code_debug_str(self->NextVar) : txt("Null") ); + break; + } + + return string_to_strc( * result ); +} + +Code code_duplicate(Code self) +{ + Code result = make_code(); + + void* mem_result = rcast(void*, cast(AST*, result)); + void* mem_self = rcast(void*, cast(AST*, self)); + mem_copy( mem_result, mem_self, sizeof( AST ) ); + + result->Parent = NullCode; + return result; +} + +String code_to_string(Code self) +{ + String result = string_make_strc( GlobalAllocator, txt("") ); + code_to_string_ptr( self, & result ); + return result; +} + +void code_to_string_ptr( Code self, String* result ) +{ + GEN_ASSERT(self != nullptr); + local_persist thread_local + char SerializationLevel = 0; + + switch ( self->Type ) + { + case CT_Invalid: + #ifdef GEN_DONT_ALLOW_INVALID_CODE + log_failure("Attempted to serialize invalid code! - %SC", Parent ? Parent->code_debug_str() : Name ); + #else + string_append_fmt( result, "Invalid Code!" ); + #endif + break; + + case CT_NewLine: + string_append_strc( result, txt("\n")); + break; + + case CT_Untyped: + case CT_Execution: + case CT_Comment: + case CT_PlatformAttributes: + string_append_strc( result, self->Content ); + break; + + case CT_Access_Private: + case CT_Access_Protected: + case CT_Access_Public: + string_append_strc( result, self->Name ); + break; + + case CT_Class: + class_to_string_def(cast(CodeClass, self), result ); + break; + + case CT_Class_Fwd: + class_to_string_fwd(cast(CodeClass, self), result ); + break; + + case CT_Constructor: + constructor_to_string_def(cast(CodeConstructor, self), result ); + break; + + case CT_Constructor_Fwd: + constructor_to_string_fwd(cast(CodeConstructor, self), result ); + break; + + case CT_Destructor: + destructor_to_string_def(cast(CodeDestructor, self), result ); + break; + + case CT_Destructor_Fwd: + destructor_to_string_fwd(cast(CodeDestructor, self), result ); + break; + + case CT_Enum: + enum_to_string_def(cast(CodeEnum, self), result ); + break; + + case CT_Enum_Fwd: + enum_to_string_fwd(cast(CodeEnum, self), result ); + break; + + case CT_Enum_Class: + enum_to_string_class_def(cast(CodeEnum, self), result ); + break; + + case CT_Enum_Class_Fwd: + enum_to_string_class_fwd(cast(CodeEnum, self), result ); + break; + + case CT_Export_Body: + body_to_string_export(cast(CodeBody, self), result ); + break; + + case CT_Extern_Linkage: + extern_to_string(cast(CodeExtern, self), result ); + break; + + case CT_Friend: + friend_to_string_ref(cast(CodeFriend, self), result ); + break; + + case CT_Function: + fn_to_string_def(cast(CodeFn, self), result ); + break; + + case CT_Function_Fwd: + fn_to_string_fwd(cast(CodeFn, self), result ); + break; + + case CT_Module: + module_to_string_ref(cast(CodeModule, self), result ); + break; + + case CT_Namespace: + namespace_to_string_ref(cast(CodeNS, self), result ); + break; + + case CT_Operator: + case CT_Operator_Member: + code_op_to_string_def(cast(CodeOperator, self), result ); + break; + + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + code_op_to_string_fwd(cast(CodeOperator, self), result ); + break; + + case CT_Operator_Cast: + opcast_to_string_def(cast(CodeOpCast, self), result ); + break; + + case CT_Operator_Cast_Fwd: + opcast_to_string_fwd(cast(CodeOpCast, self), result ); + break; + + case CT_Parameters: + params_to_string_ref(cast(CodeParams, self), result ); + break; + + case CT_Preprocess_Define: + define_to_string_ref(cast(CodeDefine, self), result ); + break; + + case CT_Preprocess_If: + preprocess_to_string_if(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_IfDef: + preprocess_to_string_ifdef(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_IfNotDef: + preprocess_to_string_ifndef(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Include: + include_to_string_ref(cast(CodeInclude, self), result ); + break; + + case CT_Preprocess_ElIf: + preprocess_to_string_elif(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Else: + preprocess_to_string_else(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_EndIf: + preprocess_to_string_endif(cast(CodePreprocessCond, self), result ); + break; + + case CT_Preprocess_Pragma: + pragma_to_string_ref(cast(CodePragma, self), result ); + break; + + case CT_Specifiers: + specifiers_to_string_ref(cast(CodeSpecifiers, self), result ); + break; + + case CT_Struct: + struct_to_string_def(cast(CodeStruct, self), result ); + break; + + case CT_Struct_Fwd: + struct_to_string_fwd(cast(CodeStruct, self), result ); + break; + + case CT_Template: + template_to_string_ref(cast(CodeTemplate, self), result ); + break; + + case CT_Typedef: + typedef_to_string_ref(cast(CodeTypedef, self), result ); + break; + + case CT_Typename: + typename_to_string_ref(cast(CodeTypename, self), result ); + break; + + case CT_Union: + union_to_string_def( cast(CodeUnion, self), result ); + break; + + case CT_Union_Fwd: + union_to_string_fwd( cast(CodeUnion, self), result ); + break; + + case CT_Using: + using_to_string_ref(cast(CodeUsing, self), result ); + break; + + case CT_Using_Namespace: + using_to_string_ns(cast(CodeUsing, self), result ); + break; + + case CT_Variable: + var_to_string_ref(cast(CodeVar, self), result ); + break; + + case CT_Enum_Body: + case CT_Class_Body: + case CT_Extern_Linkage_Body: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + body_to_string_ref( cast(CodeBody, self), result ); + break; + } +} + +bool code_is_equal( Code self, Code other ) +{ +/* + AST values are either some u32 value, a cached string, or a pointer to another AST. + + u32 values are compared by value. + Cached strings are compared by pointer. + AST nodes are compared with AST::is_equal. +*/ + if ( other == nullptr ) + { + log_fmt( "AST::is_equal: other is null\nAST: %SC", code_debug_str(self) ); + return false; + } + + if ( self->Type != other->Type ) + { + log_fmt("AST::is_equal: Type check failure with other\nAST: %SC\nOther: %SC" + , code_debug_str(self) + ,code_debug_str(other) + ); + + return false; + } + + switch ( self->Type ) + { + #define check_member_val( val ) \ + if ( self->val != other->val ) \ + { \ + log_fmt("\nAST::is_equal: Member - " #val " failed\n" \ + "AST : %SC\n" \ + "Other: %SC\n" \ + , code_debug_str(self) \ + ,code_debug_str(other) \ + ); \ + \ + return false; \ + } + + #define check_member_str( str ) \ + if ( ! strc_are_equal( self->str, other->str ) ) \ + { \ + log_fmt("\nAST::is_equal: Member string - "#str " failed\n" \ + "AST : %SC\n" \ + "Other: %SC\n" \ + , code_debug_str(self) \ + ,code_debug_str(other) \ + ); \ + \ + return false; \ + } + + #define check_member_content( content ) \ + if ( ! strc_are_equal( self->content, other->content )) \ + { \ + log_fmt("\nAST::is_equal: Member content - "#content " failed\n" \ + "AST : %SC\n" \ + "Other: %SC\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + ); \ + \ + log_fmt("Content cannot be trusted to be unique with this check " \ + "so it must be verified by eye for now\n" \ + "AST Content:\n%SC\n" \ + "Other Content:\n%SC\n" \ + , strc_visualize_whitespace(self->content, GlobalAllocator) \ + , strc_visualize_whitespace(other->content, GlobalAllocator) \ + ); \ + } + + #define check_member_ast( ast ) \ + if ( self->ast ) \ + { \ + if ( other->ast == nullptr ) \ + { \ + log_fmt("\nAST::is_equal: Failed for member " #ast " other equivalent param is null\n" \ + "AST : %SC\n" \ + "Other: %SC\n" \ + "For ast member: %SC\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + , code_debug_str(self->ast) \ + ); \ + \ + return false; \ + } \ + \ + if ( ! code_is_equal(self->ast, other->ast ) ) \ + { \ + log_fmt( "\nAST::is_equal: Failed for " #ast"\n" \ + "AST : %SC\n" \ + "Other: %SC\n" \ + "For ast member: %SC\n" \ + "other's ast member: %SC\n" \ + , code_debug_str(self) \ + , code_debug_str(other) \ + , code_debug_str(self->ast) \ + , code_debug_str(other->ast) \ + ); \ + \ + return false; \ + } \ + } + + case CT_NewLine: + case CT_Access_Public: + case CT_Access_Protected: + case CT_Access_Private: + case CT_Preprocess_Else: + case CT_Preprocess_EndIf: + return true; + + + // Comments are not validated. + case CT_Comment: + return true; + + case CT_Execution: + case CT_PlatformAttributes: + case CT_Untyped: + { + check_member_content( Content ); + return true; + } + + case CT_Class_Fwd: + case CT_Struct_Fwd: + { + check_member_str( Name ); + check_member_ast( ParentType ); + check_member_val( ParentAccess ); + check_member_ast( Attributes ); + + return true; + } + + case CT_Class: + case CT_Struct: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ParentType ); + check_member_val( ParentAccess ); + check_member_ast( Attributes ); + check_member_ast( Body ); + + return true; + } + + case CT_Constructor: + { + check_member_ast( InitializerList ); + check_member_ast( Params ); + check_member_ast( Body ); + + return true; + } + + case CT_Constructor_Fwd: + { + check_member_ast( InitializerList ); + check_member_ast( Params ); + + return true; + } + + case CT_Destructor: + { + check_member_ast( Specs ); + check_member_ast( Body ); + + return true; + } + + case CT_Destructor_Fwd: + { + check_member_ast( Specs ); + + return true; + } + + case CT_Enum: + case CT_Enum_Class: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Attributes ); + check_member_ast( UnderlyingType ); + check_member_ast( Body ); + check_member_ast( UnderlyingTypeMacro ); + + return true; + } + + case CT_Enum_Fwd: + case CT_Enum_Class_Fwd: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Attributes ); + check_member_ast( UnderlyingType ); + check_member_ast( UnderlyingTypeMacro ); + + return true; + } + + case CT_Extern_Linkage: + { + check_member_str( Name ); + check_member_ast( Body ); + + return true; + } + + case CT_Friend: + { + check_member_str( Name ); + check_member_ast( Declaration ); + + return true; + } + + case CT_Function: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ReturnType ); + check_member_ast( Attributes ); + check_member_ast( Specs ); + check_member_ast( Params ); + check_member_ast( Body ); + + return true; + } + + case CT_Function_Fwd: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ReturnType ); + check_member_ast( Attributes ); + check_member_ast( Specs ); + check_member_ast( Params ); + + return true; + } + + case CT_Module: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + + return true; + } + + case CT_Namespace: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Body ); + + return true; + } + + case CT_Operator: + case CT_Operator_Member: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ReturnType ); + check_member_ast( Attributes ); + check_member_ast( Specs ); + check_member_ast( Params ); + check_member_ast( Body ); + + return true; + } + + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ReturnType ); + check_member_ast( Attributes ); + check_member_ast( Specs ); + check_member_ast( Params ); + + return true; + } + + case CT_Operator_Cast: + { + check_member_str( Name ); + check_member_ast( Specs ); + check_member_ast( ValueType ); + check_member_ast( Body ); + + return true; + } + + case CT_Operator_Cast_Fwd: + { + check_member_str( Name ); + check_member_ast( Specs ); + check_member_ast( ValueType ); + + return true; + } + + case CT_Parameters: + { + if ( self->NumEntries > 1 ) + { + Code curr = self; + Code curr_other = other; + while ( curr != nullptr ) + { + if ( curr ) + { + if ( curr_other == nullptr ) + { + log_fmt("\nAST::is_equal: Failed for parameter, other equivalent param is null\n" + "AST : %SC\n" + "Other: %SC\n" + "For ast member: %SC\n" + , code_debug_str(curr) + ); + + return false; + } + + if ( strc_are_equal(curr->Name, curr_other->Name) ) + { + log_fmt( "\nAST::is_equal: Failed for parameter name check\n" + "AST : %SC\n" + "Other: %SC\n" + "For ast member: %SC\n" + "other's ast member: %SC\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) + ); + return false; + } + + if ( curr->ValueType && ! code_is_equal(curr->ValueType, curr_other->ValueType) ) + { + log_fmt( "\nAST::is_equal: Failed for parameter value type check\n" + "AST : %SC\n" + "Other: %SC\n" + "For ast member: %SC\n" + "other's ast member: %SC\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) + ); + return false; + } + + if ( curr->Value && ! code_is_equal(curr->Value, curr_other->Value) ) + { + log_fmt( "\nAST::is_equal: Failed for parameter value check\n" + "AST : %SC\n" + "Other: %SC\n" + "For ast member: %SC\n" + "other's ast member: %SC\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) + ); + return false; + } + } + + curr = curr->Next; + curr_other = curr_other->Next; + } + + check_member_val( NumEntries ); + + return true; + } + + check_member_str( Name ); + check_member_ast( ValueType ); + check_member_ast( Value ); + check_member_ast( ArrExpr ); + + return true; + } + + case CT_Preprocess_Define: + { + check_member_str( Name ); + check_member_content( Content ); + + return true; + } + + case CT_Preprocess_If: + case CT_Preprocess_IfDef: + case CT_Preprocess_IfNotDef: + case CT_Preprocess_ElIf: + { + check_member_content( Content ); + + return true; + } + + case CT_Preprocess_Include: + case CT_Preprocess_Pragma: + { + check_member_content( Content ); + + return true; + } + + case CT_Specifiers: + { + check_member_val( NumEntries ); + check_member_str( Name ); + for ( s32 idx = 0; idx < self->NumEntries; ++idx ) + { + check_member_val( ArrSpecs[ idx ] ); + } + return true; + } + + case CT_Template: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Params ); + check_member_ast( Declaration ); + + return true; + } + + case CT_Typedef: + { + check_member_val( IsFunction ); + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Specs ); + check_member_ast( UnderlyingType ); + + return true; + } + case CT_Typename: + { + check_member_val( IsParamPack ); + check_member_str( Name ); + check_member_ast( Specs ); + check_member_ast( ArrExpr ); + + return true; + } + + case CT_Union: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Attributes ); + check_member_ast( Body ); + + return true; + } + + case CT_Union_Fwd: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( Attributes ); + } + + case CT_Using: + case CT_Using_Namespace: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( UnderlyingType ); + check_member_ast( Attributes ); + + return true; + } + + case CT_Variable: + { + check_member_val( ModuleFlags ); + check_member_str( Name ); + check_member_ast( ValueType ); + check_member_ast( BitfieldSize ); + check_member_ast( Value ); + check_member_ast( Attributes ); + check_member_ast( Specs ); + check_member_ast( NextVar ); + + return true; + } + + case CT_Class_Body: + case CT_Enum_Body: + case CT_Export_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + { + check_member_ast( Front ); + check_member_ast( Back ); + + Code curr = self->Front; + Code curr_other = other->Front; + while ( curr != nullptr ) + { + if ( curr_other == nullptr ) + { + log_fmt("\nAST::is_equal: Failed for body, other equivalent param is null\n" + "AST : %SC\n" + "Other: %SC\n" + , code_debug_str(curr) + , code_debug_str(other) + ); + + return false; + } + + if ( ! code_is_equal( curr, curr_other ) ) + { + log_fmt( "\nAST::is_equal: Failed for body\n" + "AST : %SC\n" + "Other: %SC\n" + "For ast member: %SC\n" + "other's ast member: %SC\n" + , code_debug_str(self) + , code_debug_str(other) + , code_debug_str(curr) + , code_debug_str(curr_other) + ); + + return false; + } + + curr = curr->Next; + curr_other = curr_other->Next; + } + + check_member_val( NumEntries ); + + return true; + } + + #undef check_member_val + #undef check_member_str + #undef check_member_ast + } + + return true; +} + +bool code_validate_body(Code self) +{ +#define CheckEntries( Unallowed_Types ) \ + do \ + { \ + CodeBody body = cast(CodeBody, self); \ + for ( Code code_entry = begin_CodeBody(body); code_entry != end_CodeBody(body); next_CodeBody(body, code_entry) ) \ + { \ + switch ( code_entry->Type ) \ + { \ + Unallowed_Types \ + log_failure( "AST::validate_body: Invalid entry in body %SC", code_debug_str(code_entry) ); \ + return false; \ + } \ + } \ + } \ + while (0); + + switch ( self->Type ) + { + case CT_Class_Body: + { + CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES ); + } + break; + case CT_Enum_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) + { + if ( entry->Type != CT_Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in enum body (needs to be untyped or comment) %SC", code_debug_str(entry) ); + return false; + } + } + } + break; + case CT_Export_Body: + { + CheckEntries( GEN_AST_BODY_CLASS_UNALLOWED_TYPES ); + } + break; + case CT_Extern_Linkage: + { + CheckEntries( GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES ); + } + break; + case CT_Function_Body: + { + CheckEntries( GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES ); + } + break; + case CT_Global_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) + { + switch (entry->Type) + { + case CT_Access_Public: + case CT_Access_Protected: + case CT_Access_Private: + case CT_PlatformAttributes: + case CT_Class_Body: + case CT_Enum_Body: + case CT_Execution: + case CT_Friend: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Operator_Member: + case CT_Operator_Member_Fwd: + case CT_Parameters: + case CT_Specifiers: + case CT_Struct_Body: + case CT_Typename: + log_failure("AST::validate_body: Invalid entry in body %SC", code_debug_str(entry)); + return false; + } + } + } + break; + case CT_Namespace_Body: + { + CheckEntries( GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES ); + } + break; + case CT_Struct_Body: + { + CheckEntries( GEN_AST_BODY_STRUCT_UNALLOWED_TYPES ); + } + break; + case CT_Union_Body: + { + CodeBody body = cast(CodeBody, self); + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); next_CodeBody(body, entry) ) + { + if ( entry->Type != CT_Untyped ) + { + log_failure( "AST::validate_body: Invalid entry in union body (needs to be untyped or comment) %SC", code_debug_str(entry) ); + return false; + } + } + } + break; + + default: + log_failure( "AST::validate_body: Invalid this AST does not have a body %SC", code_debug_str(self) ); + return false; + } + + return false; + +#undef CheckEntries +} diff --git a/base/components/ast.hpp b/base/components/ast.hpp new file mode 100644 index 0000000..a40aa04 --- /dev/null +++ b/base/components/ast.hpp @@ -0,0 +1,478 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "types.hpp" +#include "gen/ecode.hpp" +#include "gen/eoperator.hpp" +#include "gen/especifier.hpp" +#endif + +/* + ______ ______ ________ __ __ ______ __ + / \ / \| \ | \ | \ / \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ | ▓▓\ | ▓▓ | ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓▓\| ▓▓ | ▓▓ \▓▓/ \ / ▓▓/ \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓▓▓\ ▓▓ | ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ \▓▓▓▓ | ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓▓ \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +struct AST; +struct AST_Body; +struct AST_Attributes; +struct AST_Comment; +struct AST_Constructor; +// struct AST_BaseClass; +struct AST_Class; +struct AST_Define; +struct AST_Destructor; +struct AST_Enum; +struct AST_Exec; +struct AST_Extern; +struct AST_Include; +struct AST_Friend; +struct AST_Fn; +struct AST_Module; +struct AST_NS; +struct AST_Operator; +struct AST_OpCast; +struct AST_Params; +struct AST_Pragma; +struct AST_PreprocessCond; +struct AST_Specifiers; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct AST_Expr; +struct AST_Expr_Assign; +struct AST_Expr_Alignof; +struct AST_Expr_Binary; +struct AST_Expr_CStyleCast; +struct AST_Expr_FunctionalCast; +struct AST_Expr_CppCast; +struct AST_Expr_ProcCall; +struct AST_Expr_Decltype; +struct AST_Expr_Comma; // TODO(Ed) : This is a binary op not sure if it needs its own AST... +struct AST_Expr_AMS; // Access Member Symbol +struct AST_Expr_Sizeof; +struct AST_Expr_Subscript; +struct AST_Expr_Ternary; +struct AST_Expr_UnaryPrefix; +struct AST_Expr_UnaryPostfix; +struct AST_Expr_Element; + +struct AST_Stmt; +struct AST_Stmt_Break; +struct AST_Stmt_Case; +struct AST_Stmt_Continue; +struct AST_Stmt_Decl; +struct AST_Stmt_Do; +struct AST_Stmt_Expr; // TODO(Ed) : Is this distinction needed? (Should it be a flag instead?) +struct AST_Stmt_Else; +struct AST_Stmt_If; +struct AST_Stmt_For; +struct AST_Stmt_Goto; +struct AST_Stmt_Label; +struct AST_Stmt_Switch; +struct AST_Stmt_While; +#endif + +struct AST_Struct; +struct AST_Template; +struct AST_Typename; +struct AST_Typedef; +struct AST_Union; +struct AST_Using; +struct AST_Var; + +#if GEN_COMPILER_C +typedef AST* Code; +#else +struct Code; +#endif + +#if GEN_COMPILER_C +typedef AST_Body* CodeBody; +typedef AST_Attributes* CodeAttributes; +typedef AST_Comment* CodeComment; +typedef AST_Class* CodeClass; +typedef AST_Constructor* CodeConstructor; +typedef AST_Define* CodeDefine; +typedef AST_Destructor* CodeDestructor; +typedef AST_Enum* CodeEnum; +typedef AST_Exec* CodeExec; +typedef AST_Extern* CodeExtern; +typedef AST_Include* CodeInclude; +typedef AST_Friend* CodeFriend; +typedef AST_Fn* CodeFn; +typedef AST_Module* CodeModule; +typedef AST_NS* CodeNS; +typedef AST_Operator* CodeOperator; +typedef AST_OpCast* CodeOpCast; +typedef AST_Params* CodeParams; +typedef AST_PreprocessCond* CodePreprocessCond; +typedef AST_Pragma* CodePragma; +typedef AST_Specifiers* CodeSpecifiers; +#else +struct CodeBody; +struct CodeAttributes; +struct CodeComment; +struct CodeClass; +struct CodeConstructor; +struct CodeDefine; +struct CodeDestructor; +struct CodeEnum; +struct CodeExec; +struct CodeExtern; +struct CodeInclude; +struct CodeFriend; +struct CodeFn; +struct CodeModule; +struct CodeNS; +struct CodeOperator; +struct CodeOpCast; +struct CodeParams; +struct CodePreprocessCond; +struct CodePragma; +struct CodeSpecifiers; +#endif + +#if GEN_EXECUTION_EXPRESSION_SUPPORT + +#if GEN_COMPILER_C +typedef AST_Expr* CodeExpr; +typedef AST_Expr_Assign* CodeExpr_Assign; +typedef AST_Expr_Alignof* CodeExpr_Alignof; +typedef AST_Expr_Binary* CodeExpr_Binary; +typedef AST_Expr_CStyleCast* CodeExpr_CStyleCast; +typedef AST_Expr_FunctionalCast* CodeExpr_FunctionalCast; +typedef AST_Expr_CppCast* CodeExpr_CppCast; +typedef AST_Expr_Element* CodeExpr_Element; +typedef AST_Expr_ProcCall* CodeExpr_ProcCall; +typedef AST_Expr_Decltype* CodeExpr_Decltype; +typedef AST_Expr_Comma* CodeExpr_Comma; +typedef AST_Expr_AMS* CodeExpr_AMS; // Access Member Symbol +typedef AST_Expr_Sizeof* CodeExpr_Sizeof; +typedef AST_Expr_Subscript* CodeExpr_Subscript; +typedef AST_Expr_Ternary* CodeExpr_Ternary; +typedef AST_Expr_UnaryPrefix* CodeExpr_UnaryPrefix; +typedef AST_Expr_UnaryPostfix* CodeExpr_UnaryPostfix; +#else +struct CodeExpr; +struct CodeExpr_Assign; +struct CodeExpr_Alignof; +struct CodeExpr_Binary; +struct CodeExpr_CStyleCast; +struct CodeExpr_FunctionalCast; +struct CodeExpr_CppCast; +struct CodeExpr_Element; +struct CodeExpr_ProcCall; +struct CodeExpr_Decltype; +struct CodeExpr_Comma; +struct CodeExpr_AMS; // Access Member Symbol +struct CodeExpr_Sizeof; +struct CodeExpr_Subscript; +struct CodeExpr_Ternary; +struct CodeExpr_UnaryPrefix; +struct CodeExpr_UnaryPostfix; +#endif + +#if GEN_COMPILER_C +typedef AST_Stmt* CodeStmt; +typedef AST_Stmt_Break* CodeStmt_Break; +typedef AST_Stmt_Case* CodeStmt_Case; +typedef AST_Stmt_Continue* CodeStmt_Continue; +typedef AST_Stmt_Decl* CodeStmt_Decl; +typedef AST_Stmt_Do* CodeStmt_Do; +typedef AST_Stmt_Expr* CodeStmt_Expr; +typedef AST_Stmt_Else* CodeStmt_Else; +typedef AST_Stmt_If* CodeStmt_If; +typedef AST_Stmt_For* CodeStmt_For; +typedef AST_Stmt_Goto* CodeStmt_Goto; +typedef AST_Stmt_Label* CodeStmt_Label; +typedef AST_Stmt_Switch* CodeStmt_Switch; +typedef AST_Stmt_While* CodeStmt_While; +#else +struct CodeStmt; +struct CodeStmt_Break; +struct CodeStmt_Case; +struct CodeStmt_Continue; +struct CodeStmt_Decl; +struct CodeStmt_Do; +struct CodeStmt_Expr; +struct CodeStmt_Else; +struct CodeStmt_If; +struct CodeStmt_For; +struct CodeStmt_Goto; +struct CodeStmt_Label; +struct CodeStmt_Switch; +struct CodeStmt_While; +#endif + +// GEN_EXECUTION_EXPRESSION_SUPPORT +#endif + +#if GEN_COMPILER_C +typedef AST_Struct* CodeStruct; +typedef AST_Template* CodeTemplate; +typedef AST_Typename* CodeTypename; +typedef AST_Typedef* CodeTypedef; +typedef AST_Union* CodeUnion; +typedef AST_Using* CodeUsing; +typedef AST_Var* CodeVar; +#else +struct CodeStruct; +struct CodeTemplate; +struct CodeTypename; +struct CodeTypedef; +struct CodeUnion; +struct CodeUsing; +struct CodeVar; +#endif + +GEN_NS_PARSER_BEGIN + +struct Token; + +GEN_NS_PARSER_END + +#if GEN_COMPILER_CPP +// Note(Ed): This is to alleviate an edge case with parsing usings or typedefs where I don't really have it setup +// to parse a 'namespace' macro or a type with a macro. +// I have ideas for ways to pack that into the typedef/using ast, but for now just keeping it like this +#define ParserTokenType GEN_NS_PARSER Token +typedef ParserTokenType Token; +#undef ParserTokenType +#endif + +#if GEN_COMPILER_CPP +template< class Type> forceinline Type tmpl_cast( Code self ) { return * rcast( Type*, & self ); } +#endif + +#pragma region Code C-Interface + +void code_append (Code code, Code other ); +StrC code_debug_str (Code code); +Code code_duplicate (Code code); +Code* code_entry (Code code, u32 idx ); +bool code_has_entries (Code code); +bool code_is_body (Code code); +bool code_is_equal (Code code, Code other); +bool code_is_valid (Code code); +void code_set_global (Code code); +String code_to_string (Code self ); +void code_to_string_ptr(Code self, String* result ); +StrC code_type_str (Code self ); +bool code_validate_body(Code self ); + +#pragma endregion Code C-Interface + +#if GEN_COMPILER_CPP +/* + AST* wrapper + - Not constantly have to append the '*' as this is written often.. + - Allows for implicit conversion to any of the ASTs (raw or filtered). +*/ +struct Code +{ + AST* ast; + +# define Using_Code( Typename ) \ + forceinline StrC debug_str() { return code_debug_str(* this); } \ + forceinline Code duplicate() { return code_duplicate(* this); } \ + forceinline bool is_equal( Code other ) { return code_is_equal(* this, other); } \ + forceinline bool is_body() { return code_is_body(* this); } \ + forceinline bool is_valid() { return code_is_valid(* this); } \ + forceinline void set_global() { return code_set_global(* this); } + +# define Using_CodeOps( Typename ) \ + forceinline Typename& operator = ( Code other ); \ + forceinline bool operator ==( Code other ) { return (AST*)ast == other.ast; } \ + forceinline bool operator !=( Code other ) { return (AST*)ast != other.ast; } \ + forceinline bool operator ==(std::nullptr_t) const { return ast == nullptr; } \ + forceinline bool operator !=(std::nullptr_t) const { return ast != nullptr; } \ + operator bool(); + +#if ! GEN_C_LIKE_CPP + Using_Code( Code ); + forceinline void append(Code other) { return code_append(* this, other); } + forceinline Code* entry(u32 idx) { return code_entry(* this, idx); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline String to_string() { return code_to_string(* this); } + forceinline void to_string(String& result) { return code_to_string_ptr(* this, & result); } + forceinline StrC type_str() { return code_type_str(* this); } + forceinline bool validate_body() { return code_validate_body(*this); } +#endif + + Using_CodeOps( Code ); + forceinline AST* operator ->() { return ast; } + + Code& operator ++(); + + // TODO(Ed) : Remove this overload. + auto& operator*() + { + local_persist thread_local + Code NullRef = { nullptr }; + + if ( ast == nullptr ) + return NullRef; + + return *this; + } + +#ifdef GEN_ENFORCE_STRONG_CODE_TYPES +# define operator explicit operator +#endif + operator CodeBody() const; + operator CodeAttributes() const; + // operator CodeBaseClass() const; + operator CodeComment() const; + operator CodeClass() const; + operator CodeConstructor() const; + operator CodeDefine() const; + operator CodeDestructor() const; + operator CodeExec() const; + operator CodeEnum() const; + operator CodeExtern() const; + operator CodeInclude() const; + operator CodeFriend() const; + operator CodeFn() const; + operator CodeModule() const; + operator CodeNS() const; + operator CodeOperator() const; + operator CodeOpCast() const; + operator CodeParams() const; + operator CodePragma() const; + operator CodePreprocessCond() const; + operator CodeSpecifiers() const; + operator CodeStruct() const; + operator CodeTemplate() const; + operator CodeTypename() const; + operator CodeTypedef() const; + operator CodeUnion() const; + operator CodeUsing() const; + operator CodeVar() const; + #undef operator +}; +#endif + +#pragma region Statics +// Used to identify ASTs that should always be duplicated. (Global constant ASTs) +extern Code Code_Global; + +// Used to identify invalid generated code. +extern Code Code_Invalid; +#pragma endregion Statics + +struct Code_POD +{ + AST* ast; +}; +static_assert( sizeof(Code) == sizeof(Code_POD), "ERROR: Code is not POD" ); + +// Desired width of the AST data structure. +constexpr int const AST_POD_Size = 128; + +constexpr static +int AST_ArrSpecs_Cap = +( + AST_POD_Size + - sizeof(Code) + - sizeof(StringCached) + - sizeof(Code) * 2 + - sizeof(Token*) + - sizeof(Code) + - sizeof(CodeType) + - sizeof(ModuleFlag) + - sizeof(u32) +) +/ sizeof(Specifier) - 1; + +/* + Simple AST POD with functionality to seralize into C++ syntax. +*/ +struct AST +{ + union { + struct + { + Code InlineCmt; // Class, Constructor, Destructor, Enum, Friend, Functon, Operator, OpCast, Struct, Typedef, Using, Variable + Code Attributes; // Class, Enum, Function, Struct, Typedef, Union, Using, Variable + Code Specs; // Destructor, Function, Operator, Typename, Variable + union { + Code InitializerList; // Constructor + Code ParentType; // Class, Struct, ParentType->Next has a possible list of interfaces. + Code ReturnType; // Function, Operator, Typename + Code UnderlyingType; // Enum, Typedef + Code ValueType; // Parameter, Variable + }; + union { + Code Macro; // Parameter + Code BitfieldSize; // Variable (Class/Struct Data Member) + Code Params; // Constructor, Function, Operator, Template, Typename + Code UnderlyingTypeMacro; // Enum + }; + union { + Code ArrExpr; // Typename + Code Body; // Class, Constructor, Destructor, Enum, Friend, Function, Namespace, Struct, Union + Code Declaration; // Friend, Template + Code Value; // Parameter, Variable + }; + union { + Code NextVar; // Variable; Possible way to handle comma separated variables declarations. ( , NextVar->Specs NextVar->Name NextVar->ArrExpr = NextVar->Value ) + Code SuffixSpecs; // Only used with typenames, to store the function suffix if typename is function signature. ( May not be needed ) + Code PostNameMacro; // Only used with parameters for specifically UE_REQUIRES (Thanks Unreal) + }; + }; + StringCached Content; // Attributes, Comment, Execution, Include + struct { + Specifier ArrSpecs[AST_ArrSpecs_Cap]; // Specifiers + Code NextSpecs; // Specifiers; If ArrSpecs is full, then NextSpecs is used. + }; + }; + StringCached Name; + union { + Code Prev; + Code Front; + Code Last; + }; + union { + Code Next; + Code Back; + }; + Token* Token; // Reference to starting token, only avaialble if it was derived from parsing. + Code Parent; + CodeType Type; +// CodeFlag CodeFlags; + ModuleFlag ModuleFlags; + union { + b32 IsFunction; // Used by typedef to not serialize the name field. + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; + Operator Op; + AccessSpec ParentAccess; + s32 NumEntries; + s32 VarParenthesizedInit; // Used by variables to know that initialization is using a constructor expression instead of an assignment expression. + }; +}; +static_assert( sizeof(AST) == AST_POD_Size, "ERROR: AST is not size of AST_POD_Size" ); + +#if GEN_COMPILER_CPP +// Uses an implicitly overloaded cast from the AST to the desired code type. +// Necessary if the user wants GEN_ENFORCE_STRONG_CODE_TYPES +struct InvalidCode_ImplictCaster; +#define InvalidCode (InvalidCode_ImplictCaster{}) +#else +#define InvalidCode (void*){ (void*)Code_Invalid } +#endif + +#if GEN_COMPILER_CPP +struct NullCode_ImplicitCaster; +// Used when the its desired when omission is allowed in a definition. +#define NullCode (NullCode_ImplicitCaster{}) +#else +#define NullCode nullptr +#endif diff --git a/base/components/ast_case_macros.cpp b/base/components/ast_case_macros.cpp new file mode 100644 index 0000000..8f1c9fa --- /dev/null +++ b/base/components/ast_case_macros.cpp @@ -0,0 +1,78 @@ +# define GEN_AST_BODY_CLASS_UNALLOWED_TYPES \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Extern_Linkage: \ + case CT_Function_Body: \ + case CT_Function_Fwd: \ + case CT_Global_Body: \ + case CT_Namespace: \ + case CT_Namespace_Body: \ + case CT_Operator: \ + case CT_Operator_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename: +# define GEN_AST_BODY_STRUCT_UNALLOWED_TYPES GEN_AST_BODY_CLASS_UNALLOWED_TYPES + +# define GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Extern_Linkage: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Function_Fwd: \ + case CT_Global_Body: \ + case CT_Namespace: \ + case CT_Namespace_Body: \ + case CT_Operator: \ + case CT_Operator_Fwd: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename: + +# define GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Execution: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Namespace_Body: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename: +# define GEN_AST_BODY_EXPORT_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES +# define GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES + +# define GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES \ + case CT_Access_Public: \ + case CT_Access_Protected: \ + case CT_Access_Private: \ + case CT_PlatformAttributes: \ + case CT_Class_Body: \ + case CT_Enum_Body: \ + case CT_Execution: \ + case CT_Friend: \ + case CT_Function_Body: \ + case CT_Namespace_Body: \ + case CT_Operator_Member: \ + case CT_Operator_Member_Fwd: \ + case CT_Parameters: \ + case CT_Specifiers: \ + case CT_Struct_Body: \ + case CT_Typename: diff --git a/project/components/ast_types.hpp b/base/components/ast_types.hpp similarity index 68% rename from project/components/ast_types.hpp rename to base/components/ast_types.hpp index 04817ca..6385d3a 100644 --- a/project/components/ast_types.hpp +++ b/base/components/ast_types.hpp @@ -4,6 +4,22 @@ #endif #pragma region AST Types + +/* + ______ ______ ________ ________ + / \ / \| \ | \ +| ▓▓▓▓▓▓\ ▓▓▓▓▓▓\\▓▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓▓__ __ ______ ______ _______ +| ▓▓__| ▓▓ ▓▓___\▓▓ | ▓▓ | ▓▓ | \ | \/ \ / \ / \ +| ▓▓ ▓▓\▓▓ \ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ +| ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ | ▓▓ | ▓▓ | ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓\▓▓ \ +| ▓▓ | ▓▓ \__| ▓▓ | ▓▓ | ▓▓ | ▓▓__/ ▓▓ ▓▓__/ ▓▓ ▓▓▓▓▓▓▓▓_\▓▓▓▓▓▓\ +| ▓▓ | ▓▓\▓▓ ▓▓ | ▓▓ | ▓▓ \▓▓ ▓▓ ▓▓ ▓▓\▓▓ \ ▓▓ + \▓▓ \▓▓ \▓▓▓▓▓▓ \▓▓ \▓▓ _\▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓▓▓▓▓▓ + | \__| ▓▓ ▓▓ + \▓▓ ▓▓ ▓▓ + \▓▓▓▓▓▓ \▓▓ +*/ + /* Show only relevant members of the AST for its type. AST* fields are replaced with Code types. @@ -12,13 +28,15 @@ struct AST_Body { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StringCached Name; Code Front; Code Back; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; s32 NumEntries; }; @@ -27,15 +45,15 @@ static_assert( sizeof(AST_Body) == sizeof(AST), "ERROR: AST_Body is not the same struct AST_Attributes { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is not the same size as AST"); @@ -44,14 +62,14 @@ static_assert( sizeof(AST_Attributes) == sizeof(AST), "ERROR: AST_Attributes is struct AST_BaseClass { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is not the same size as AST"); @@ -60,15 +78,15 @@ static_assert( sizeof(AST_BaseClass) == sizeof(AST), "ERROR: AST_BaseClass is no struct AST_Comment { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not the same size as AST"); @@ -76,24 +94,24 @@ static_assert( sizeof(AST_Comment) == sizeof(AST), "ERROR: AST_Comment is not th struct AST_Class { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; // Only supported by forward declarations CodeAttributes Attributes; char _PAD_SPECS_ [ sizeof(AST*) ]; - CodeType ParentType; + CodeTypename ParentType; char _PAD_PARAMS_[ sizeof(AST*) ]; CodeBody Body; char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - CodeType Prev; - CodeType Next; - parser::Token* Tok; - Code Parent; StringCached Name; - CodeT Type; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; ModuleFlag ModuleFlags; AccessSpec ParentAccess; }; @@ -102,24 +120,24 @@ static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the sa struct AST_Constructor { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; // Only supported by forward declarations char _PAD_PROPERTIES_ [ sizeof(AST*) * 1 ]; CodeSpecifiers Specs; Code InitializerList; - CodeParam Params; + CodeParams Params; Code Body; char _PAD_PROPERTIES_2_ [ sizeof(AST*) * 2 ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor is not the same size as AST"); @@ -127,15 +145,15 @@ static_assert( sizeof(AST_Constructor) == sizeof(AST), "ERROR: AST_Constructor i struct AST_Define { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST"); @@ -143,7 +161,7 @@ static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the struct AST_Destructor { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; @@ -154,12 +172,12 @@ struct AST_Destructor char _PAD_PROPERTIES_3_ [ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is not the same size as AST"); @@ -167,41 +185,41 @@ static_assert( sizeof(AST_Destructor) == sizeof(AST), "ERROR: AST_Destructor is struct AST_Enum { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; char _PAD_SPEC_ [ sizeof(AST*) ]; - CodeType UnderlyingType; - char _PAD_PARAMS_[ sizeof(AST*) ]; + CodeTypename UnderlyingType; + Code UnderlyingTypeMacro; CodeBody Body; char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; - char _PAD_UNUSED_[ sizeof(u32) ]; + char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Enum) == sizeof(AST), "ERROR: AST_Enum is not the same size as AST"); struct AST_Exec { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same size as AST"); @@ -210,14 +228,14 @@ static_assert( sizeof(AST_Exec) == sizeof(AST), "ERROR: AST_Exec is not the same struct AST_Expr { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr) == sizeof(AST), "ERROR: AST_Expr is not the same size as AST"); @@ -225,14 +243,14 @@ static_assert( sizeof(AST_Expr) == sizeof(AST), "ERROR: AST_Expr is not the same struct AST_Expr_Assign { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Assign) == sizeof(AST), "ERROR: AST_Expr_Assign is not the same size as AST"); @@ -240,14 +258,14 @@ static_assert( sizeof(AST_Expr_Assign) == sizeof(AST), "ERROR: AST_Expr_Assign i struct AST_Expr_Alignof { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Alignof) == sizeof(AST), "ERROR: AST_Expr_Alignof is not the same size as AST"); @@ -255,14 +273,14 @@ static_assert( sizeof(AST_Expr_Alignof) == sizeof(AST), "ERROR: AST_Expr_Alignof struct AST_Expr_Binary { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Binary) == sizeof(AST), "ERROR: AST_Expr_Binary is not the same size as AST"); @@ -270,14 +288,14 @@ static_assert( sizeof(AST_Expr_Binary) == sizeof(AST), "ERROR: AST_Expr_Binary i struct AST_Expr_CStyleCast { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_CStyleCast) == sizeof(AST), "ERROR: AST_Expr_CStyleCast is not the same size as AST"); @@ -285,14 +303,14 @@ static_assert( sizeof(AST_Expr_CStyleCast) == sizeof(AST), "ERROR: AST_Expr_CSty struct AST_Expr_FunctionalCast { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_FunctionalCast) == sizeof(AST), "ERROR: AST_Expr_FunctionalCast is not the same size as AST"); @@ -300,14 +318,14 @@ static_assert( sizeof(AST_Expr_FunctionalCast) == sizeof(AST), "ERROR: AST_Expr_ struct AST_Expr_CppCast { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_CppCast) == sizeof(AST), "ERROR: AST_Expr_CppCast is not the same size as AST"); @@ -315,14 +333,14 @@ static_assert( sizeof(AST_Expr_CppCast) == sizeof(AST), "ERROR: AST_Expr_CppCast struct AST_Expr_ProcCall { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_ProcCall) == sizeof(AST), "ERROR: AST_Expr_Identifier is not the same size as AST"); @@ -330,14 +348,14 @@ static_assert( sizeof(AST_Expr_ProcCall) == sizeof(AST), "ERROR: AST_Expr_Identi struct AST_Expr_Decltype { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Decltype) == sizeof(AST), "ERROR: AST_Expr_Decltype is not the same size as AST"); @@ -345,14 +363,14 @@ static_assert( sizeof(AST_Expr_Decltype) == sizeof(AST), "ERROR: AST_Expr_Declty struct AST_Expr_Comma { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Comma) == sizeof(AST), "ERROR: AST_Expr_Comma is not the same size as AST"); @@ -360,14 +378,14 @@ static_assert( sizeof(AST_Expr_Comma) == sizeof(AST), "ERROR: AST_Expr_Comma is struct AST_Expr_AMS { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_AMS) == sizeof(AST), "ERROR: AST_Expr_AMS is not the same size as AST"); @@ -375,14 +393,14 @@ static_assert( sizeof(AST_Expr_AMS) == sizeof(AST), "ERROR: AST_Expr_AMS is not struct AST_Expr_Sizeof { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Sizeof) == sizeof(AST), "ERROR: AST_Expr_Sizeof is not the same size as AST"); @@ -390,14 +408,14 @@ static_assert( sizeof(AST_Expr_Sizeof) == sizeof(AST), "ERROR: AST_Expr_Sizeof i struct AST_Expr_Subscript { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Subscript) == sizeof(AST), "ERROR: AST_Expr_Subscript is not the same size as AST"); @@ -405,14 +423,14 @@ static_assert( sizeof(AST_Expr_Subscript) == sizeof(AST), "ERROR: AST_Expr_Subsc struct AST_Expr_Ternary { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Ternary) == sizeof(AST), "ERROR: AST_Expr_Ternary is not the same size as AST"); @@ -420,14 +438,14 @@ static_assert( sizeof(AST_Expr_Ternary) == sizeof(AST), "ERROR: AST_Expr_Ternary struct AST_Expr_UnaryPrefix { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_UnaryPrefix) == sizeof(AST), "ERROR: AST_Expr_UnaryPrefix is not the same size as AST"); @@ -435,14 +453,14 @@ static_assert( sizeof(AST_Expr_UnaryPrefix) == sizeof(AST), "ERROR: AST_Expr_Una struct AST_Expr_UnaryPostfix { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_UnaryPostfix) == sizeof(AST), "ERROR: AST_Expr_UnaryPostfix is not the same size as AST"); @@ -450,14 +468,14 @@ static_assert( sizeof(AST_Expr_UnaryPostfix) == sizeof(AST), "ERROR: AST_Expr_Un struct AST_Expr_Element { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Expr_Element) == sizeof(AST), "ERROR: AST_Expr_Element is not the same size as AST"); @@ -466,7 +484,7 @@ static_assert( sizeof(AST_Expr_Element) == sizeof(AST), "ERROR: AST_Expr_Element struct AST_Extern { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; @@ -474,12 +492,12 @@ struct AST_Extern char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the same size as AST"); @@ -487,15 +505,15 @@ static_assert( sizeof(AST_Extern) == sizeof(AST), "ERROR: AST_Extern is not the struct AST_Include { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not the same size as AST"); @@ -503,7 +521,7 @@ static_assert( sizeof(AST_Include) == sizeof(AST), "ERROR: AST_Include is not th struct AST_Friend { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; @@ -512,12 +530,12 @@ struct AST_Friend char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the same size as AST"); @@ -525,24 +543,24 @@ static_assert( sizeof(AST_Friend) == sizeof(AST), "ERROR: AST_Friend is not the struct AST_Fn { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; CodeSpecifiers Specs; - CodeType ReturnType; - CodeParam Params; + CodeTypename ReturnType; + CodeParams Params; CodeBody Body; char _PAD_PROPERTIES_ [ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -550,13 +568,15 @@ static_assert( sizeof(AST_Fn) == sizeof(AST), "ERROR: AST_Fn is not the same siz struct AST_Module { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + union { + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; + }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -565,19 +585,19 @@ static_assert( sizeof(AST_Module) == sizeof(AST), "ERROR: AST_Module is not the struct AST_NS { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_PROPERTIES_[ sizeof(AST*) * 5 ]; CodeBody Body; char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -586,91 +606,91 @@ static_assert( sizeof(AST_NS) == sizeof(AST), "ERROR: AST_NS is not the same siz struct AST_Operator { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; CodeSpecifiers Specs; - CodeType ReturnType; - CodeParam Params; + CodeTypename ReturnType; + CodeParams Params; CodeBody Body; char _PAD_PROPERTIES_ [ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; - OperatorT Op; + Operator Op; }; static_assert( sizeof(AST_Operator) == sizeof(AST), "ERROR: AST_Operator is not the same size as AST"); struct AST_OpCast { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - CodeComment InlineCmt; - char _PAD_PROPERTIES_[ sizeof(AST*) ]; - CodeSpecifiers Specs; - CodeType ValueType; - char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; - CodeBody Body; - char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; + CodeComment InlineCmt; + char _PAD_PROPERTIES_[ sizeof(AST*) ]; + CodeSpecifiers Specs; + CodeTypename ValueType; + char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; + CodeBody Body; + char _PAD_PROPERTIES_3_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_OpCast) == sizeof(AST), "ERROR: AST_OpCast is not the same size as AST"); -struct AST_Param +struct AST_Params { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { - char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; - CodeType ValueType; - Code Macro; - Code Value; - Code PostNameMacro; // Thanks Unreal + char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; + CodeTypename ValueType; + Code Macro; + Code Value; + Code PostNameMacro; // Thanks Unreal // char _PAD_PROPERTIES_3_[sizeof( AST* )]; }; }; - CodeParam Last; - CodeParam Next; - parser::Token* Tok; - Code Parent; StringCached Name; - CodeT Type; + CodeParams Last; + CodeParams Next; + Token* Tok; + Code Parent; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; s32 NumEntries; }; -static_assert( sizeof(AST_Param) == sizeof(AST), "ERROR: AST_Param is not the same size as AST"); +static_assert( sizeof(AST_Params) == sizeof(AST), "ERROR: AST_Params is not the same size as AST"); struct AST_Pragma { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST"); @@ -678,29 +698,29 @@ static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the struct AST_PreprocessCond { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; StringCached Content; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST"); struct AST_Specifiers { - SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ]; + Specifier ArrSpecs[ AST_ArrSpecs_Cap ]; + StringCached Name; CodeSpecifiers NextSpecs; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; s32 NumEntries; }; @@ -710,14 +730,14 @@ static_assert( sizeof(AST_Specifiers) == sizeof(AST), "ERROR: AST_Specifier is n struct AST_Stmt { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt) == sizeof(AST), "ERROR: AST_Stmt is not the same size as AST"); @@ -725,14 +745,14 @@ static_assert( sizeof(AST_Stmt) == sizeof(AST), "ERROR: AST_Stmt is not the same struct AST_Stmt_Break { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Break) == sizeof(AST), "ERROR: AST_Stmt_Break is not the same size as AST"); @@ -740,14 +760,14 @@ static_assert( sizeof(AST_Stmt_Break) == sizeof(AST), "ERROR: AST_Stmt_Break is struct AST_Stmt_Case { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Case) == sizeof(AST), "ERROR: AST_Stmt_Case is not the same size as AST"); @@ -755,14 +775,14 @@ static_assert( sizeof(AST_Stmt_Case) == sizeof(AST), "ERROR: AST_Stmt_Case is no struct AST_Stmt_Continue { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Continue) == sizeof(AST), "ERROR: AST_Stmt_Continue is not the same size as AST"); @@ -770,14 +790,14 @@ static_assert( sizeof(AST_Stmt_Continue) == sizeof(AST), "ERROR: AST_Stmt_Contin struct AST_Stmt_Decl { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Decl) == sizeof(AST), "ERROR: AST_Stmt_Decl is not the same size as AST"); @@ -785,14 +805,14 @@ static_assert( sizeof(AST_Stmt_Decl) == sizeof(AST), "ERROR: AST_Stmt_Decl is no struct AST_Stmt_Do { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Do) == sizeof(AST), "ERROR: AST_Stmt_Do is not the same size as AST"); @@ -800,14 +820,14 @@ static_assert( sizeof(AST_Stmt_Do) == sizeof(AST), "ERROR: AST_Stmt_Do is not th struct AST_Stmt_Expr { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Expr) == sizeof(AST), "ERROR: AST_Stmt_Expr is not the same size as AST"); @@ -815,14 +835,14 @@ static_assert( sizeof(AST_Stmt_Expr) == sizeof(AST), "ERROR: AST_Stmt_Expr is no struct AST_Stmt_Else { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Else) == sizeof(AST), "ERROR: AST_Stmt_Else is not the same size as AST"); @@ -830,14 +850,14 @@ static_assert( sizeof(AST_Stmt_Else) == sizeof(AST), "ERROR: AST_Stmt_Else is no struct AST_Stmt_If { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_If) == sizeof(AST), "ERROR: AST_Stmt_If is not the same size as AST"); @@ -845,14 +865,14 @@ static_assert( sizeof(AST_Stmt_If) == sizeof(AST), "ERROR: AST_Stmt_If is not th struct AST_Stmt_For { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_For) == sizeof(AST), "ERROR: AST_Stmt_For is not the same size as AST"); @@ -860,14 +880,14 @@ static_assert( sizeof(AST_Stmt_For) == sizeof(AST), "ERROR: AST_Stmt_For is not struct AST_Stmt_Goto { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Goto) == sizeof(AST), "ERROR: AST_Stmt_Goto is not the same size as AST"); @@ -875,14 +895,14 @@ static_assert( sizeof(AST_Stmt_Goto) == sizeof(AST), "ERROR: AST_Stmt_Goto is no struct AST_Stmt_Label { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Label) == sizeof(AST), "ERROR: AST_Stmt_Label is not the same size as AST"); @@ -890,14 +910,14 @@ static_assert( sizeof(AST_Stmt_Label) == sizeof(AST), "ERROR: AST_Stmt_Label is struct AST_Stmt_Switch { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_Switch) == sizeof(AST), "ERROR: AST_Stmt_Switch is not the same size as AST"); @@ -905,14 +925,14 @@ static_assert( sizeof(AST_Stmt_Switch) == sizeof(AST), "ERROR: AST_Stmt_Switch i struct AST_Stmt_While { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; }; + StringCached Name; CodeExpr Prev; CodeExpr Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ]; }; static_assert( sizeof(AST_Stmt_While) == sizeof(AST), "ERROR: AST_Stmt_While is not the same size as AST"); @@ -921,24 +941,24 @@ static_assert( sizeof(AST_Stmt_While) == sizeof(AST), "ERROR: AST_Stmt_While is struct AST_Struct { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; char _PAD_SPECS_ [ sizeof(AST*) ]; - CodeType ParentType; + CodeTypename ParentType; char _PAD_PARAMS_[ sizeof(AST*) ]; CodeBody Body; char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; - CodeType Prev; - CodeType Next; - parser::Token* Tok; - Code Parent; StringCached Name; - CodeT Type; + CodeTypename Prev; + CodeTypename Next; + Token* Tok; + Code Parent; + CodeType Type; ModuleFlag ModuleFlags; AccessSpec ParentAccess; }; @@ -947,21 +967,21 @@ static_assert( sizeof(AST_Struct) == sizeof(AST), "ERROR: AST_Struct is not the struct AST_Template { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_PROPERTIES_[ sizeof(AST*) * 4 ]; - CodeParam Params; + CodeParams Params; Code Declaration; char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -972,61 +992,64 @@ static_assert( sizeof(AST_Template) == sizeof(AST), "ERROR: AST_Template is not struct AST_Type { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_INLINE_CMT_[ sizeof(AST*) ]; - CodeAttributes Attributes; - CodeSpecifiers Specs; - Code QualifierID; - // CodeType ReturnType; // Only used for function signatures - // CodeParam Params; // Only used for function signatures - Code ArrExpr; + CodeAttributes Attributes; + CodeSpecifiers Specs; + Code QualifierID; + // CodeTypename ReturnType; // Only used for function signatures + // CodeParams Params; // Only used for function signatures + Code ArrExpr; // CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; b32 IsParamPack; }; static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); #endif -struct AST_Type +struct AST_Typename { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_INLINE_CMT_[ sizeof(AST*) ]; CodeAttributes Attributes; CodeSpecifiers Specs; - CodeType ReturnType; // Only used for function signatures - CodeParam Params; // Only used for function signatures + CodeTypename ReturnType; // Only used for function signatures + CodeParams Params; // Only used for function signatures Code ArrExpr; CodeSpecifiers SpecsFuncSuffix; // Only used for function signatures }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; char _PAD_UNUSED_[ sizeof(ModuleFlag) ]; - b32 IsParamPack; + struct { + b16 IsParamPack; // Used by typename to know if type should be considered a parameter pack. + ETypenameTag TypeTag; // Used by typename to keep track of explicitly declared tags for the identifier (enum, struct, union) + }; }; -static_assert( sizeof(AST_Type) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); +static_assert( sizeof(AST_Typename) == sizeof(AST), "ERROR: AST_Type is not the same size as AST"); struct AST_Typedef { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; @@ -1035,12 +1058,12 @@ struct AST_Typedef char _PAD_PROPERTIES_2_[ sizeof(AST*) * 3 ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; b32 IsFunction; }; @@ -1049,7 +1072,7 @@ static_assert( sizeof(AST_Typedef) == sizeof(AST), "ERROR: AST_Typedef is not th struct AST_Union { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { char _PAD_INLINE_CMT_[ sizeof(AST*) ]; @@ -1059,12 +1082,12 @@ struct AST_Union char _PAD_PROPERTIES_2_[ sizeof(AST*) ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -1073,22 +1096,22 @@ static_assert( sizeof(AST_Union) == sizeof(AST), "ERROR: AST_Union is not the sa struct AST_Using { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; char _PAD_SPECS_ [ sizeof(AST*) ]; - CodeType UnderlyingType; + CodeTypename UnderlyingType; char _PAD_PROPERTIES_[ sizeof(AST*) * 3 ]; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; char _PAD_UNUSED_[ sizeof(u32) ]; }; @@ -1097,26 +1120,26 @@ static_assert( sizeof(AST_Using) == sizeof(AST), "ERROR: AST_Using is not the sa struct AST_Var { union { - char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap + sizeof(AST*) ]; + char _PAD_[ sizeof(Specifier) * AST_ArrSpecs_Cap + sizeof(AST*) ]; struct { CodeComment InlineCmt; CodeAttributes Attributes; CodeSpecifiers Specs; - CodeType ValueType; + CodeTypename ValueType; Code BitfieldSize; Code Value; CodeVar NextVar; }; }; + StringCached Name; Code Prev; Code Next; - parser::Token* Tok; + Token* Tok; Code Parent; - StringCached Name; - CodeT Type; + CodeType Type; ModuleFlag ModuleFlags; - s32 VarConstructorInit; + s32 VarParenthesizedInit; }; static_assert( sizeof(AST_Var) == sizeof(AST), "ERROR: AST_Var is not the same size as AST"); diff --git a/base/components/code_serialization.cpp b/base/components/code_serialization.cpp new file mode 100644 index 0000000..5e0a4f4 --- /dev/null +++ b/base/components/code_serialization.cpp @@ -0,0 +1,1492 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "ast.cpp" +#endif + +inline +String attributes_to_string(CodeAttributes attributes) { + GEN_ASSERT(attributes); + char* raw = ccast(char*, strc_duplicate( attributes->Content, GlobalAllocator ).Ptr); + String result = { raw }; + return result; +} + +inline +void attributes_to_string_ref(CodeAttributes attributes, String* result) { + GEN_ASSERT(attributes); + GEN_ASSERT(result); + string_append_strc(result, attributes->Content); +} + +String body_to_string(CodeBody body) +{ + GEN_ASSERT(body); + String result = string_make_reserve( GlobalAllocator, 128 ); + switch ( body->Type ) + { + case CT_Untyped: + case CT_Execution: + string_append_strc( & result, cast(Code, body)->Content ); + break; + + case CT_Enum_Body: + case CT_Class_Body: + case CT_Extern_Linkage_Body: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + body_to_string_ref( body, & result ); + break; + + case CT_Export_Body: + body_to_string_export( body, & result ); + break; + } + return result; +} + +void body_to_string_ref( CodeBody body, String* result ) +{ + GEN_ASSERT(body != nullptr); + GEN_ASSERT(result != nullptr); + Code curr = body->Front; + s32 left = body->NumEntries; + while ( left -- ) + { + code_to_string_ptr(curr, result); + // string_append_fmt( result, "%S", code_to_string(curr) ); + ++curr; + } +} + +void body_to_string_export( CodeBody body, String* result ) +{ + GEN_ASSERT(body != nullptr); + GEN_ASSERT(result != nullptr); + string_append_fmt( result, "export\n{\n" ); + + Code curr = cast(Code, body); + s32 left = body->NumEntries; + while ( left-- ) + { + code_to_string_ptr(curr, result); + // string_append_fmt( result, "%S", code_to_string(curr) ); + ++curr; + } + + string_append_fmt( result, "};\n" ); +} + +inline +String comment_to_string(CodeComment comment) { + GEN_ASSERT(comment); + char* raw = ccast(char*, strc_duplicate( comment->Content, GlobalAllocator ).Ptr); + String result = { raw }; + return result; +} + +inline +void comment_to_string_ref(CodeComment comment, String* result) { + GEN_ASSERT(comment); + GEN_ASSERT(result); + string_append_strc(result, comment->Content); +} + +String constructor_to_string(CodeConstructor self) +{ + String result = string_make_reserve( GlobalAllocator, 128 ); + switch (self->Type) + { + case CT_Constructor: + constructor_to_string_def( self, & result ); + break; + case CT_Constructor_Fwd: + constructor_to_string_fwd( self, & result ); + break; + } + return result; +} + +void constructor_to_string_def(CodeConstructor self, String* result ) +{ + Code ClassStructParent = self->Parent->Parent; + if (ClassStructParent) { + string_append_strc( result, ClassStructParent->Name ); + } + else { + string_append_strc( result, self->Name ); + } + + if ( self->Params ) + string_append_fmt( result, "( %S )", params_to_string(self->Params) ); + else + string_append_strc( result, txt("()") ); + + if ( self->InitializerList ) + string_append_fmt( result, " : %S", code_to_string(self->InitializerList) ); + + if ( self->InlineCmt ) + string_append_fmt( result, " // %SC", self->InlineCmt->Content ); + + string_append_fmt( result, "\n{\n%S\n}\n", code_to_string(self->Body) ); +} + +void constructor_to_string_fwd(CodeConstructor self, String* result ) +{ + Code ClassStructParent = self->Parent->Parent; + if (ClassStructParent) { + string_append_strc( result, ClassStructParent->Name ); + } + else { + string_append_strc( result, self->Name ); + } + + if ( self->Params ) + string_append_fmt( result, "( %S )", params_to_string(self->Params) ); + else + string_append_fmt( result, "()"); + + if (self->Body) + string_append_fmt( result, " = %S", code_to_string(self->Body) ); + + if ( self->InlineCmt ) + string_append_fmt( result, "; // %SC\n", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n") ); +} + +String class_to_string( CodeClass self ) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Class: + class_to_string_def(self, & result ); + break; + case CT_Class_Fwd: + class_to_string_fwd(self, & result ); + break; + } + return result; +} + +void class_to_string_def( CodeClass self, String* result ) +{ + GEN_ASSERT(self); + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("class ") ); + + if ( self->Attributes ) + { + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + } + + if ( self->ParentType ) + { + StrC access_level = access_spec_to_str( self->ParentAccess ); + string_append_fmt( result, "%SC : %SC %S", self->Name, access_level, typename_to_string(self->ParentType) ); + + CodeTypename interface = cast(CodeTypename, self->ParentType->Next); + if ( interface ) + string_append_strc( result, txt("\n") ); + + while ( interface ) + { + string_append_fmt( result, ", public %S", typename_to_string(interface) ); + interface = interface->Next ? cast(CodeTypename, interface->Next) : NullCode; + } + } + else if ( self->Name.Len ) + { + string_append_strc( result, self->Name ); + } + + if ( self->InlineCmt ) + { + string_append_fmt( result, " // %SC", self->InlineCmt->Content ); + } + + string_append_fmt( result, "\n{\n%S\n}", body_to_string(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n") ); +} + +void class_to_string_fwd( CodeClass self, String* result ) +{ + GEN_ASSERT(self); + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "class %S %SC", attributes_to_string(self->Attributes), self->Name ); + + else string_append_fmt( result, "class %SC", self->Name ); + + // Check if it can have an end-statement + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + string_append_fmt( result, "; // %SC\n", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n") ); + } +} + +String define_to_string(CodeDefine define) +{ + return string_fmt_buf( GlobalAllocator, "#define %SC %SC", define->Name, define->Content ); +} + +void define_to_string_ref(CodeDefine define, String* result ) +{ + string_append_fmt( result, "#define %SC %SC", define->Name, define->Content ); +} + +String destructor_to_string(CodeDestructor self) +{ + String result = string_make_reserve( GlobalAllocator, 128 ); + switch ( self->Type ) + { + case CT_Destructor: + destructor_to_string_def( self, & result ); + break; + case CT_Destructor_Fwd: + destructor_to_string_fwd( self, & result ); + break; + } + return result; +} + +void destructor_to_string_def(CodeDestructor self, String* result ) +{ + if ( self->Name.Len ) + { + string_append_fmt( result, "%SC()", self->Name ); + } + else if ( self->Specs ) + { + if ( specifiers_has(self->Specs, Spec_Virtual ) ) + string_append_fmt( result, "virtual ~%SC()", self->Parent->Name ); + else + string_append_fmt( result, "~%SC()", self->Parent->Name ); + } + else + string_append_fmt( result, "~%SC()", self->Parent->Name ); + + string_append_fmt( result, "\n{\n%S\n}\n", code_to_string(self->Body) ); +} + +void destructor_to_string_fwd(CodeDestructor self, String* result ) +{ + if ( self->Specs ) + { + if ( specifiers_has(self->Specs, Spec_Virtual ) ) + string_append_fmt( result, "virtual ~%SC();\n", self->Parent->Name ); + else + string_append_fmt( result, "~%SC()", self->Parent->Name ); + + if ( specifiers_has(self->Specs, Spec_Pure ) ) + string_append_strc( result, txt(" = 0;") ); + else if (self->Body) + string_append_fmt( result, " = %S;", code_to_string(self->Body) ); + } + else + string_append_fmt( result, "~%SC();", self->Parent->Name ); + + if ( self->InlineCmt ) + string_append_fmt( result, " %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt("\n")); +} + +String enum_to_string(CodeEnum self) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Enum: + enum_to_string_def(self, & result ); + break; + case CT_Enum_Fwd: + enum_to_string_fwd(self, & result ); + break; + case CT_Enum_Class: + enum_to_string_class_def(self, & result ); + break; + case CT_Enum_Class_Fwd: + enum_to_string_class_fwd(self, & result ); + break; + } + return result; +} + +void enum_to_string_def(CodeEnum self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes || self->UnderlyingType || self->UnderlyingTypeMacro ) + { + string_append_strc( result, txt("enum ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->UnderlyingType ) + string_append_fmt( result, "%SC : %S\n{\n%S\n}" + , self->Name + , typename_to_string(self->UnderlyingType) + , body_to_string(self->Body) + ); + else if ( self->UnderlyingTypeMacro ) + string_append_fmt( result, "%SC %S\n{\n%S\n}" + , self->Name + , code_to_string(self->UnderlyingTypeMacro) + , body_to_string(self->Body) + ); + + else string_append_fmt( result, "%SC\n{\n%S\n}", self->Name, body_to_string(self->Body) ); + } + else string_append_fmt( result, "enum %SC\n{\n%S\n}", self->Name, body_to_string(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n")); +} + +void enum_to_string_fwd(CodeEnum self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->UnderlyingType ) + string_append_fmt( result, "enum %SC : %S", self->Name, typename_to_string(self->UnderlyingType) ); + else if (self->UnderlyingTypeMacro) + { + log_fmt("IDENTIFIED A UNDERLYING ENUM MACRO"); + string_append_fmt( result, "enum %SC %S", self->Name, code_to_string(self->UnderlyingTypeMacro) ); + } + else + string_append_fmt( result, "enum %SC", self->Name ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n")); + } +} + +void enum_to_string_class_def(CodeEnum self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes || self->UnderlyingType ) + { + string_append_strc( result, txt("enum class ") ); + + if ( self->Attributes ) + { + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + } + + if ( self->UnderlyingType ) + { + string_append_fmt( result, "%SC : %S\n{\n%S\n}", self->Name, typename_to_string(self->UnderlyingType), body_to_string(self->Body) ); + } + else + { + string_append_fmt( result, "%SC\n{\n%S\n}", self->Name, body_to_string(self->Body) ); + } + } + else + { + string_append_fmt( result, "enum %SC\n{\n%S\n}", self->Name, body_to_string(self->Body) ); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n")); +} + +void enum_to_string_class_fwd(CodeEnum self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("enum class ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + string_append_fmt( result, "%SC : %S", self->Name, typename_to_string(self->UnderlyingType) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n")); + } +} + +String exec_to_string(CodeExec exec) +{ + GEN_ASSERT(exec); + char* raw = ccast(char*, strc_duplicate( exec->Content, GlobalAllocator ).Ptr); + String result = { raw }; + return result; +} + +void extern_to_string(CodeExtern self, String* result ) +{ + if ( self->Body ) + string_append_fmt( result, "extern \"%SC\"\n{\n%S\n}\n", self->Name, body_to_string(self->Body) ); + else + string_append_fmt( result, "extern \"%SC\"\n{}\n", self->Name ); +} + +String include_to_string(CodeInclude include) +{ + return string_fmt_buf( GlobalAllocator, "#include %SC\n", include->Content ); +} + +void include_to_string_ref( CodeInclude include, String* result ) +{ + string_append_fmt( result, "#include %SC\n", include->Content ); +} + +String friend_to_string(CodeFriend self) +{ + String result = string_make_reserve( GlobalAllocator, 256 ); + friend_to_string_ref( self, & result ); + return result; +} + +void friend_to_string_ref(CodeFriend self, String* result ) +{ + string_append_fmt( result, "friend %S", code_to_string(self->Declaration) ); + + if ( self->Declaration->Type != CT_Function && self->Declaration->Type != CT_Operator && (* result)[ string_length(* result) - 1 ] != ';' ) + { + string_append_strc( result, txt(";") ); + } + + if ( self->InlineCmt ) + string_append_fmt( result, " %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt("\n")); +} + +String fn_to_string(CodeFn self) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Function: + fn_to_string_def(self, & result ); + break; + case CT_Function_Fwd: + fn_to_string_fwd(self, & result ); + break; + } + return result; +} + +void fn_to_string_def(CodeFn self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export") ); + + if ( self->Attributes ) + string_append_fmt( result, " %S ", attributes_to_string(self->Attributes) ); + + bool prefix_specs = false; + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + + prefix_specs = true; + } + } + } + + if ( self->Attributes || prefix_specs ) + string_append_strc( result, txt("\n") ); + + if ( self->ReturnType ) + string_append_fmt( result, "%S %SC(", typename_to_string(self->ReturnType), self->Name ); + + else + string_append_fmt( result, "%SC(", self->Name ); + + if ( self->Params ) + string_append_fmt( result, "%S)", params_to_string(self->Params) ); + + else + string_append_strc( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + string_append_fmt( result, "\n{\n%S\n}\n", body_to_string(self->Body) ); +} + +void fn_to_string_fwd(CodeFn self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + b32 prefix_specs = false; + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) || ! ( * spec != Spec_Pure) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + + prefix_specs = true; + } + } + } + + if ( self->Attributes || prefix_specs ) + { + string_append_strc( result, txt("\n") ); + } + + if ( self->ReturnType ) + string_append_fmt( result, "%S %SC(", typename_to_string(self->ReturnType), self->Name ); + + else + string_append_fmt( result, "%SC(", self->Name ); + + if ( self->Params ) + string_append_fmt( result, "%S)", params_to_string(self->Params) ); + + else + string_append_strc( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Specs && specifiers_has(self->Specs, Spec_Pure ) >= 0 ) + string_append_strc( result, txt(" = 0;") ); + else if (self->Body) + string_append_fmt( result, " = %S;", body_to_string(self->Body) ); + + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n") ); +} + +String module_to_string(CodeModule self) +{ + String result = string_make_reserve( GlobalAllocator, 64 ); + module_to_string_ref( self, & result ); + return result; +} + +void module_to_string_ref(CodeModule self, String* result ) +{ + if (((scast(u32, ModuleFlag_Export) & scast(u32, self->ModuleFlags)) == scast(u32, ModuleFlag_Export))) + string_append_strc( result, txt("export ")); + + if (((scast(u32, ModuleFlag_Import) & scast(u32, self->ModuleFlags)) == scast(u32, ModuleFlag_Import))) + string_append_strc( result, txt("import ")); + + string_append_fmt( result, "%SC;\n", self->Name ); +} + +String namespace_to_string(CodeNS self) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + namespace_to_string_ref( self, & result ); + return result; +} + +void namespace_to_string_ref(CodeNS self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_fmt( result, "namespace %SC\n{\n%S\n}\n", self->Name, body_to_string(self->Body) ); +} + +String code_op_to_string(CodeOperator self) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Operator: + case CT_Operator_Member: + code_op_to_string_def( self, & result ); + break; + case CT_Operator_Fwd: + case CT_Operator_Member_Fwd: + code_op_to_string_fwd( self, & result ); + break; + } + return result; +} + +void code_op_to_string_def(CodeOperator self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Attributes || self->Specs ) + { + string_append_strc( result, txt("\n") ); + } + + if ( self->ReturnType ) + string_append_fmt( result, "%S %SC (", typename_to_string(self->ReturnType), self->Name ); + + if ( self->Params ) + string_append_fmt( result, "%S)", params_to_string(self->Params) ); + + else + string_append_strc( result, txt(")") ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + string_append_fmt( result, "\n{\n%S\n}\n" + , body_to_string(self->Body) + ); +} + +void code_op_to_string_fwd(CodeOperator self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S\n", attributes_to_string(self->Attributes) ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->Attributes || self->Specs ) + { + string_append_strc( result, txt("\n") ); + } + + string_append_fmt( result, "%S %SC (", typename_to_string(self->ReturnType), self->Name ); + + if ( self->Params ) + string_append_fmt( result, "%S)", params_to_string(self->Params) ); + + else + string_append_fmt( result, ")" ); + + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + } + + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n") ); +} + +String opcast_to_string(CodeOpCast self) +{ + String result = string_make_reserve( GlobalAllocator, 128 ); + switch ( self->Type ) + { + case CT_Operator_Cast: + opcast_to_string_def(self, & result ); + break; + case CT_Operator_Cast_Fwd: + opcast_to_string_fwd(self, & result ); + break; + } + return result; +} + +void opcast_to_string_def(CodeOpCast self, String* result ) +{ + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, "%*s ", spec_str.Len, spec_str.Ptr ); + } + } + + if ( self->Name.Ptr && self->Name.Len ) + string_append_fmt( result, "%SC operator %S()", self->Name, typename_to_string(self->ValueType) ); + else + string_append_fmt( result, "operator %S()", typename_to_string(self->ValueType) ); + + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %.*s", spec_str.Len, spec_str.Ptr ); + } + } + + string_append_fmt( result, "\n{\n%S\n}\n", body_to_string(self->Body) ); + return; + } + + if ( self->Name.Ptr && self->Name.Len ) + string_append_fmt( result, "%SC operator %S()\n{\n%S\n}\n", self->Name, typename_to_string(self->ValueType), body_to_string(self->Body) ); + else + string_append_fmt( result, "operator %S()\n{\n%S\n}\n", typename_to_string(self->ValueType), body_to_string(self->Body) ); +} + +void opcast_to_string_fwd(CodeOpCast self, String* result ) +{ + if ( self->Specs ) + { + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( ! spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, "%*s ", spec_str.Len, spec_str.Ptr ); + } + } + + string_append_fmt( result, "operator %S()", typename_to_string(self->ValueType) ); + + for ( Specifier* spec = begin_CodeSpecifiers(self->Specs); spec != end_CodeSpecifiers(self->Specs); spec = next_CodeSpecifiers(self->Specs, spec) ) + { + if ( spec_is_trailing( * spec ) ) + { + StrC spec_str = spec_to_str( * spec ); + string_append_fmt( result, " %*s", spec_str.Len, spec_str.Ptr ); + } + } + + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt(";\n") ); + return; + } + + if ( self->InlineCmt ) + string_append_fmt( result, "operator %S(); %S", typename_to_string(self->ValueType) ); + else + string_append_fmt( result, "operator %S();\n", typename_to_string(self->ValueType) ); +} + +String params_to_string(CodeParams self) +{ + GEN_ASSERT(self); + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 128 ); + params_to_string_ref( self, & result ); + return result; +} + +void params_to_string_ref( CodeParams self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Macro ) + { + // Related to parsing: ( , ... ) + string_append_strc( result, self->Macro->Content ); + // Could also be: ( , ... ) + } + + if ( self->Name.Ptr && self->Name.Len ) + { + if ( self->ValueType == nullptr ) + string_append_fmt( result, " %SC", self->Name ); + else + string_append_fmt( result, " %S %SC", typename_to_string(self->ValueType), self->Name ); + + } + else if ( self->ValueType ) + string_append_fmt( result, " %S", typename_to_string(self->ValueType) ); + + if ( self->PostNameMacro ) + { + string_append_fmt( result, " %S", code_to_string(self->PostNameMacro) ); + } + + if ( self->Value ) + string_append_fmt( result, " = %S", code_to_string(self->Value) ); + + if ( self->NumEntries - 1 > 0 ) + { + for ( CodeParams param = begin_CodeParams(self->Next); param != end_CodeParams(self->Next); param = next_CodeParams(self->Next, param) ) + { + string_append_fmt( result, ", %S", params_to_string(param) ); + } + } +} + +String preprocess_to_string(CodePreprocessCond self) +{ + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 256 ); + switch ( self->Type ) + { + case CT_Preprocess_If: + preprocess_to_string_if( self, & result ); + break; + case CT_Preprocess_IfDef: + preprocess_to_string_ifdef( self, & result ); + break; + case CT_Preprocess_IfNotDef: + preprocess_to_string_ifndef( self, & result ); + break; + case CT_Preprocess_ElIf: + preprocess_to_string_elif( self, & result ); + break; + case CT_Preprocess_Else: + preprocess_to_string_else( self, & result ); + break; + case CT_Preprocess_EndIf: + preprocess_to_string_endif( self, & result ); + break; + } + return result; +} + +void preprocess_to_string_if(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_fmt( result, "#if %SC", cond->Content ); +} + +void preprocess_to_string_ifdef(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_fmt( result, "#ifdef %SC\n", cond->Content ); +} + +void preprocess_to_string_ifndef(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_fmt( result, "#ifndef %SC", cond->Content ); +} + +void preprocess_to_string_elif(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_fmt( result, "#elif %SC\n", cond->Content ); +} + +void preprocess_to_string_else(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_strc( result, txt("#else\n") ); +} + +void preprocess_to_string_endif(CodePreprocessCond cond, String* result ) +{ + GEN_ASSERT(cond); + string_append_strc( result, txt("#endif\n") ); +} + +String pragma_to_string(CodePragma self) +{ + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 256 ); + pragma_to_string_ref( self, & result ); + return result; +} + +void pragma_to_string_ref(CodePragma self, String* result ) +{ + string_append_fmt( result, "#pragma %SC\n", self->Content ); +} + +String specifiers_to_string(CodeSpecifiers self) +{ + String result = string_make_reserve( GlobalAllocator, 64 ); + specifiers_to_string_ref( self, & result ); + return result; +} + +void specifiers_to_string_ref( CodeSpecifiers self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + s32 idx = 0; + s32 left = self->NumEntries; + while ( left-- ) + { + StrC spec = spec_to_str( self->ArrSpecs[idx] ); + string_append_fmt( result, "%.*s ", spec.Len, spec.Ptr ); + idx++; + } +} + +String struct_to_string(CodeStruct self) +{ + GEN_ASSERT(self); + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Struct: + struct_to_string_def( self, & result ); + break; + case CT_Struct_Fwd: + struct_to_string_fwd( self, & result ); + break; + } + return result; +} + +void struct_to_string_def( CodeStruct self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("struct ") ); + + if ( self->Attributes ) + { + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + } + + if ( self->ParentType ) + { + StrC access_level = access_spec_to_str( self->ParentAccess ); + + string_append_fmt( result, "%SC : %SC %S", self->Name, access_level, typename_to_string(self->ParentType) ); + + CodeTypename interface = cast(CodeTypename, self->ParentType->Next); + if ( interface ) + string_append_strc( result, txt("\n") ); + + while ( interface ) + { + string_append_fmt( result, ", %S", typename_to_string(interface) ); + interface = interface->Next ? cast( CodeTypename, interface->Next) : NullCode; + } + } + else if ( self->Name.Len ) + { + string_append_strc( result, self->Name ); + } + + if ( self->InlineCmt ) + { + string_append_fmt( result, " // %SC", self->InlineCmt->Content ); + } + + string_append_fmt( result, "\n{\n%S\n}", body_to_string(self->Body) ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n")); +} + +void struct_to_string_fwd( CodeStruct self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "struct %S %SC", attributes_to_string(self->Attributes), self->Name ); + + else string_append_fmt( result, "struct %SC", self->Name ); + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + { + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content ); + else + string_append_strc( result, txt( ";\n") ); + } +} + +String template_to_string(CodeTemplate self) +{ + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 1024 ); + template_to_string_ref( self, & result ); + return result; +} + +void template_to_string_ref(CodeTemplate self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Params ) + string_append_fmt( result, "template< %S >\n%S", params_to_string(self->Params), code_to_string(self->Declaration) ); + else + string_append_fmt( result, "template<>\n%S", code_to_string(self->Declaration) ); +} + +String typedef_to_string(CodeTypedef self) +{ + String result = string_make_reserve( GlobalAllocator, 128 ); + typedef_to_string_ref( self, & result ); + return result; +} + +void typedef_to_string_ref(CodeTypedef self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("typedef ")); + + // Determines if the typedef is a function typename + if ( self->UnderlyingType->ReturnType ) + string_append_string( result, code_to_string(self->UnderlyingType) ); + else + string_append_fmt( result, "%S %SC", code_to_string(self->UnderlyingType), self->Name ); + + if ( self->UnderlyingType->Type == CT_Typename && self->UnderlyingType->ArrExpr ) + { + string_append_fmt( result, "[ %S ];", code_to_string(self->UnderlyingType->ArrExpr) ); + + Code next_arr_expr = self->UnderlyingType->ArrExpr->Next; + while ( next_arr_expr ) + { + string_append_fmt( result, "[ %S ];", code_to_string(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + else + { + string_append_strc( result, txt(";") ); + } + + if ( self->InlineCmt ) + string_append_fmt( result, " %SC", self->InlineCmt->Content); + else + string_append_strc( result, txt("\n")); +} + +String typename_to_string(CodeTypename self) +{ + String result = string_make_strc( GlobalAllocator, txt("") ); + typename_to_string_ref( self, & result ); + return result; +} + +void typename_to_string_ref(CodeTypename self, String* result ) +{ + #if defined(GEN_USE_NEW_TYPENAME_PARSING) + if ( self->ReturnType && self->Params ) + { + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + else + { + if ( self->Specs ) + string_append_fmt( result, "%S ( %SC ) ( %S ) %S", typename_to_string(self->ReturnType), self->Name, params_to_string(self->Params), specifiers_to_string(self->Specs) ); + else + string_append_fmt( result, "%S ( %SC ) ( %S )", typename_to_string(self->ReturnType), self->Name, params_to_string(self->Params) ); + } + + break; + } + #else + if ( self->ReturnType && self->Params ) + { + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + else + { + if ( self->Specs ) + string_append_fmt( result, "%S %SC ( %S ) %S", typename_to_string(self->ReturnType), self->Name, params_to_string(self->Params), specifiers_to_string(self->Specs) ); + else + string_append_fmt( result, "%S %SC ( %S )", typename_to_string(self->ReturnType), self->Name, params_to_string(self->Params) ); + } + + return; + } + #endif + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + switch ( self->TypeTag ) + { + case Tag_Class : string_append_strc( result, txt("class ")); break; + case Tag_Enum : string_append_strc( result, txt("enum ")); break; + case Tag_Struct : string_append_strc( result, txt("struct ")); break; + case Tag_Union : string_append_strc( result, txt("union ")); break; + default: + break; + } + + if ( self->Specs ) + string_append_fmt( result, "%SC %S", self->Name, specifiers_to_string(self->Specs) ); + else + string_append_fmt( result, "%SC", self->Name ); + + if ( self->IsParamPack ) + string_append_strc( result, txt("...")); +} + +String union_to_string(CodeUnion self) +{ + String result = string_make_reserve( GlobalAllocator, 512 ); + switch ( self->Type ) + { + case CT_Union: + union_to_string_def( self, & result ); + break; + case CT_Union_Fwd: + union_to_string_fwd( self, & result ); + break; + } + return result; +} + +void union_to_string_def(CodeUnion self, String* result ) +{ + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("union ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->Name.Len ) + { + string_append_fmt( result, "%SC\n{\n%S\n}" + , self->Name + , body_to_string(self->Body) + ); + } + else + { + // Anonymous union + string_append_fmt( result, "\n{\n%S\n}" + , body_to_string(self->Body) + ); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n")); +} + +void union_to_string_fwd(CodeUnion self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + string_append_strc( result, txt("union ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->Name.Len ) + { + string_append_fmt( result, "%SC", self->Name); + } + + if ( self->Parent == nullptr || ( self->Parent->Type != CT_Typedef && self->Parent->Type != CT_Variable ) ) + string_append_strc( result, txt(";\n")); +} + +String using_to_string(CodeUsing self) +{ + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 128 ); + switch ( self->Type ) + { + case CT_Using: + using_to_string_ref( self, & result ); + break; + case CT_Using_Namespace: + using_to_string_ns( self, & result ); + break; + } + return result; +} + +void using_to_string_ref(CodeUsing self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes ) + string_append_fmt( result, "%S ", attributes_to_string(self->Attributes) ); + + if ( self->UnderlyingType ) + { + string_append_fmt( result, "using %SC = %S", self->Name, typename_to_string(self->UnderlyingType) ); + + if ( self->UnderlyingType->ArrExpr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(self->UnderlyingType->ArrExpr) ); + + Code next_arr_expr = self->UnderlyingType->ArrExpr->Next; + while ( next_arr_expr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + string_append_strc( result, txt(";") ); + } + else + string_append_fmt( result, "using %SC;", self->Name ); + + if ( self->InlineCmt ) + string_append_fmt( result, " %SC\n", self->InlineCmt->Content ); + else + string_append_strc( result, txt("\n")); +} + +inline +void using_to_string_ns(CodeUsing self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->InlineCmt ) + string_append_fmt( result, "using namespace $SC; %SC", self->Name, self->InlineCmt->Content ); + else + string_append_fmt( result, "using namespace %SC;\n", self->Name ); +} + +inline +String var_to_string(CodeVar self) +{ + GEN_ASSERT(self); + String result = string_make_reserve( GlobalAllocator, 256 ); + var_to_string_ref( self, & result ); + return result; +} + +neverinline +void var_to_string_ref(CodeVar self, String* result ) +{ + GEN_ASSERT(self); + GEN_ASSERT(result); + if ( self->Parent && self->Parent->Type == CT_Variable ) + { + // Its a comma-separated variable ( a NextVar ) + + if ( self->Specs ) + string_append_fmt( result, "%S ", specifiers_to_string(self->Specs) ); + + string_append_strc( result, self->Name ); + + if ( self->ValueType->ArrExpr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + string_append_fmt( result, "( %S ", code_to_string(self->Value) ); + else + string_append_fmt( result, " = %S", code_to_string(self->Value) ); + } + + // Keep the chain going... + if ( self->NextVar ) + string_append_fmt( result, ", %S", var_to_string(self->NextVar) ); + + if ( self->VarParenthesizedInit ) + string_append_strc( result, txt(" )")); + + return; + } + + if ( bitfield_is_equal( u32, self->ModuleFlags, ModuleFlag_Export )) + string_append_strc( result, txt("export ") ); + + if ( self->Attributes || self->Specs ) + { + if ( self->Attributes ) + string_append_fmt( result, "%S ", specifiers_to_string(self->Specs) ); + + if ( self->Specs ) + string_append_fmt( result, "%S\n", specifiers_to_string(self->Specs) ); + + string_append_fmt( result, "%S %SC", typename_to_string(self->ValueType), self->Name ); + + if ( self->ValueType->ArrExpr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + if ( self->BitfieldSize ) + string_append_fmt( result, " : %S", code_to_string(self->BitfieldSize) ); + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + string_append_fmt( result, "( %S ", code_to_string(self->Value) ); + else + string_append_fmt( result, " = %S", code_to_string(self->Value) ); + } + + if ( self->NextVar ) + string_append_fmt( result, ", %S", var_to_string(self->NextVar) ); + + if ( self->VarParenthesizedInit ) + string_append_strc( result, txt(" )")); + + if ( self->InlineCmt ) + string_append_fmt( result, "; %SC", self->InlineCmt->Content); + else + string_append_strc( result, txt(";\n") ); + + return; + } + + if ( self->BitfieldSize ) + string_append_fmt( result, "%S %SC : %S", typename_to_string(self->ValueType), self->Name, code_to_string(self->BitfieldSize) ); + + else if ( self->ValueType->ArrExpr ) + { + string_append_fmt( result, "%S %SC[ %S ]", typename_to_string(self->ValueType), self->Name, code_to_string(self->ValueType->ArrExpr) ); + + Code next_arr_expr = self->ValueType->ArrExpr->Next; + while ( next_arr_expr ) + { + string_append_fmt( result, "[ %S ]", code_to_string(next_arr_expr) ); + next_arr_expr = next_arr_expr->Next; + } + } + + else + string_append_fmt( result, "%S %SC", typename_to_string(self->ValueType), self->Name ); + + if ( self->Value ) + { + if ( self->VarParenthesizedInit ) + string_append_fmt( result, "( %S ", code_to_string(self->Value) ); + else + string_append_fmt( result, " = %S", code_to_string(self->Value) ); + } + + if ( self->NextVar ) + string_append_fmt( result, ", %S", var_to_string( self->NextVar) ); + + if ( self->VarParenthesizedInit ) + string_append_strc( result, txt(" )")); + + string_append_strc( result, txt(";") ); + + if ( self->InlineCmt ) + string_append_fmt( result, " %SC", self->InlineCmt->Content); + else + string_append_strc( result, txt("\n")); +} diff --git a/base/components/code_types.hpp b/base/components/code_types.hpp new file mode 100644 index 0000000..22ae89e --- /dev/null +++ b/base/components/code_types.hpp @@ -0,0 +1,1130 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "ast.hpp" +#endif + +/* + ______ __ ______ __ ______ + / \ | \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ ____| ▓▓ ______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ \▓▓/ \ / ▓▓/ \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ __| ▓▓ | ▓▓ ▓▓ | ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__/ \ ▓▓__/ ▓▓ ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ ▓▓\▓▓ ▓▓\▓▓ \ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +#pragma region Code Type C-Interface + +void body_append ( CodeBody body, Code other ); +void body_append_body ( CodeBody body, CodeBody other ); +String body_to_string ( CodeBody body ); +void body_to_string_ref ( CodeBody body, String* result ); +void body_to_string_export( CodeBody body, String* result ); + +Code begin_CodeBody( CodeBody body); +Code end_CodeBody ( CodeBody body ); +Code next_CodeBody ( CodeBody body, Code entry_iter ); + +void class_add_interface( CodeClass self, CodeTypename interface ); +String class_to_string ( CodeClass self ); +void class_to_string_def( CodeClass self, String* result ); +void class_to_string_fwd( CodeClass self, String* result ); + +void params_append (CodeParams params, CodeParams param ); +CodeParams params_get (CodeParams params, s32 idx); +bool params_has_entries (CodeParams params ); +String params_to_string (CodeParams params ); +void params_to_string_ref(CodeParams params, String* result ); + +CodeParams begin_CodeParams(CodeParams params); +CodeParams end_CodeParams (CodeParams params); +CodeParams next_CodeParams (CodeParams params, CodeParams entry_iter); + +bool specifiers_append (CodeSpecifiers specifiers, Specifier spec); +s32 specifiers_has (CodeSpecifiers specifiers, Specifier spec); +s32 specifiers_remove (CodeSpecifiers specifiers, Specifier to_remove ); +String specifiers_to_string (CodeSpecifiers specifiers); +void specifiers_to_string_ref(CodeSpecifiers specifiers, String* result); + +Specifier* begin_CodeSpecifiers(CodeSpecifiers specifiers); +Specifier* end_CodeSpecifiers (CodeSpecifiers specifiers); +Specifier* next_CodeSpecifiers (CodeSpecifiers specifiers, Specifier* spec_iter); + +void struct_add_interface(CodeStruct self, CodeTypename interface); +String struct_to_string (CodeStruct self); +void struct_to_string_fwd(CodeStruct self, String* result); +void struct_to_string_def(CodeStruct self, String* result); + +String attributes_to_string (CodeAttributes attributes); +void attributes_to_string_ref(CodeAttributes attributes, String* result); + +String comment_to_string (CodeComment comment ); +void comment_to_string_ref(CodeComment comment, String* result ); + +String constructor_to_string (CodeConstructor constructor); +void constructor_to_string_def(CodeConstructor constructor, String* result ); +void constructor_to_string_fwd(CodeConstructor constructor, String* result ); + +String define_to_string (CodeDefine self); +void define_to_string_ref(CodeDefine self, String* result); + +String destructor_to_string (CodeDestructor destructor); +void destructor_to_string_def(CodeDestructor destructor, String* result ); +void destructor_to_string_fwd(CodeDestructor destructor, String* result ); + +String enum_to_string (CodeEnum self); +void enum_to_string_def (CodeEnum self, String* result ); +void enum_to_string_fwd (CodeEnum self, String* result ); +void enum_to_string_class_def(CodeEnum self, String* result ); +void enum_to_string_class_fwd(CodeEnum self, String* result ); + +String exec_to_string (CodeExec exec); +void exec_to_string_ref(CodeExec exec, String* result); + +void extern_to_string(CodeExtern self, String* result); + +String include_to_string (CodeInclude self); +void include_to_string_ref(CodeInclude self, String* result); + +String friend_to_string (CodeFriend self); +void friend_to_string_ref(CodeFriend self, String* result); + +String fn_to_string (CodeFn self); +void fn_to_string_def(CodeFn self, String* result); +void fn_to_string_fwd(CodeFn self, String* result); + +String module_to_string (CodeModule self); +void module_to_string_ref(CodeModule self, String* result); + +String namespace_to_string (CodeNS self); +void namespace_to_string_ref(CodeNS self, String* result); + +String code_op_to_string (CodeOperator self); +void code_op_to_string_fwd(CodeOperator self, String* result ); +void code_op_to_string_def(CodeOperator self, String* result ); + +String opcast_to_string (CodeOpCast op_cast ); +void opcast_to_string_def(CodeOpCast op_cast, String* result ); +void opcast_to_string_fwd(CodeOpCast op_cast, String* result ); + +String pragma_to_string (CodePragma self); +void pragma_to_string_ref(CodePragma self, String* result); + +String preprocess_to_string (CodePreprocessCond cond); +void preprocess_to_string_if (CodePreprocessCond cond, String* result ); +void preprocess_to_string_ifdef (CodePreprocessCond cond, String* result ); +void preprocess_to_string_ifndef(CodePreprocessCond cond, String* result ); +void preprocess_to_string_elif (CodePreprocessCond cond, String* result ); +void preprocess_to_string_else (CodePreprocessCond cond, String* result ); +void preprocess_to_string_endif (CodePreprocessCond cond, String* result ); + +String template_to_string (CodeTemplate self); +void template_to_string_ref(CodeTemplate self, String* result); + +String typename_to_string (CodeTypename self); +void typename_to_string_ref(CodeTypename self, String* result); + +String typedef_to_string (CodeTypedef self); +void typedef_to_string_ref(CodeTypedef self, String* result ); + +String union_to_string (CodeUnion self); +void union_to_string_def(CodeUnion self, String* result); +void union_to_string_fwd(CodeUnion self, String* result); + +String using_to_string (CodeUsing op_cast ); +void using_to_string_ref(CodeUsing op_cast, String* result ); +void using_to_string_ns (CodeUsing op_cast, String* result ); + +String var_to_string (CodeVar self); +void var_to_string_ref(CodeVar self, String* result); + +#pragma endregion Code Type C-Interface + +#if GEN_COMPILER_CPP +#pragma region Code Types C++ + +// These structs are not used at all by the C vairant. +static_assert( GEN_COMPILER_CPP, "This should not be compiled with the C-library" ); + +#define Verify_POD(Type) static_assert(size_of(Code##Type) == size_of(AST_##Type), "ERROR: Code##Type is not a POD") + +struct CodeBody +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeBody ); + forceinline void append( Code other ) { return body_append( *this, other ); } + forceinline void append( CodeBody body ) { return body_append(*this, body); } + forceinline bool has_entries() { return code_has_entries(* this); } + forceinline String to_string() { return body_to_string(* this); } + forceinline void to_string( String& result ) { return body_to_string_ref(* this, & result ); } + forceinline void to_string_export( String& result ) { return body_to_string_export(* this, & result); } + + forceinline Code begin() { return begin_CodeBody(* this); } + forceinline Code end() { return end_CodeBody(* this); } +#endif + Using_CodeOps( CodeBody ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Body* operator->() { return ast; } + AST_Body* ast; +}; + +struct CodeClass +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeClass ); + forceinline void add_interface( CodeType interface ); + forceinline String to_string(); + forceinline void to_string_def( String& result ); + forceinline void to_string_fwd( String& result ); +#endif + Using_CodeOps( CodeClass ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Class* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Class* ast; +}; + +struct CodeParams +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeParams ); + forceinline void append( CodeParams other ); + forceinline CodeParams get( s32 idx ); + forceinline bool has_entries(); + forceinline String to_string(); + forceinline void to_string( String& result ); + + forceinline CodeParams begin() { return begin_CodeParams(* this); } + forceinline CodeParams end() { return end_CodeParams(* this); } +#endif + Using_CodeOps( CodeParams ); + forceinline operator Code() { return { (AST*)ast }; } + forceinline CodeParams operator*() { return * this; } + forceinline AST_Params* operator->() { + GEN_ASSERT(ast); + return ast; + } + CodeParams& operator++(); + AST_Params* ast; +}; + +struct CodeSpecifiers +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeSpecifiers ); + bool append( Specifier spec ) { return specifiers_append(* this, spec); } + s32 has( Specifier spec ) { return specifiers_has(* this, spec); } + s32 remove( Specifier to_remove ) { return specifiers_remove(* this, to_remove); } + String to_string() { return specifiers_to_string(* this ); } + void to_string( String& result ) { return specifiers_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeSpecifiers); + forceinline operator Code() { return { (AST*) ast }; } + forceinline AST_Specifiers* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Specifiers* ast; +}; + +struct CodeAttributes +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeAttributes); + forceinline String to_string() { return attributes_to_string(* this); } + forceinline void to_string(String& result) { return attributes_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeAttributes); + operator Code(); + AST_Attributes *operator->(); + AST_Attributes *ast; +}; + +// Define_CodeType( BaseClass ); + +struct CodeComment +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeComment); + forceinline String to_string() { return comment_to_string (* this); } + forceinline void to_string(String& result) { return comment_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeComment); + operator Code(); + AST_Comment *operator->(); + AST_Comment *ast; +}; + +struct CodeConstructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeConstructor ); + forceinline String to_string() { return constructor_to_string(* this); } + forceinline void to_string_def( String& result ) { return constructor_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return constructor_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeConstructor); + operator Code(); + AST_Constructor* operator->(); + AST_Constructor* ast; +}; + +struct CodeDefine +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDefine ); + forceinline String to_string() { return define_to_string(* this); } + forceinline void to_string( String& result ) { return define_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeDefine); + operator Code(); + AST_Define* operator->(); + AST_Define* ast; +}; + +struct CodeDestructor +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeDestructor ); + forceinline String to_string() { return destructor_to_string(* this); } + forceinline void to_string_def( String& result ) { return destructor_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return destructor_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeDestructor); + operator Code(); + AST_Destructor* operator->(); + AST_Destructor* ast; +}; + +struct CodeEnum +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeEnum ); + forceinline String to_string() { return enum_to_string(* this); } + forceinline void to_string_def( String& result ) { return enum_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return enum_to_string_fwd(* this, & result); } + forceinline void to_string_class_def( String& result ) { return enum_to_string_class_def(* this, & result); } + forceinline void to_string_class_fwd( String& result ) { return enum_to_string_class_fwd(* this, & result); } +#endif + Using_CodeOps(CodeEnum); + operator Code(); + AST_Enum* operator->(); + AST_Enum* ast; +}; + +struct CodeExec +{ +#if ! GEN_C_LIKE_CPP + Using_Code(CodeExec); + forceinline String to_string() { return exec_to_string(* this); } + forceinline void to_string(String& result) { return exec_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeExec); + operator Code(); + AST_Exec *operator->(); + AST_Exec *ast; +}; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeExpr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr* operator->(); + AST_Expr* ast; +}; + +struct CodeExpr_Assign +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Assign ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Assign* operator->(); + AST_Expr_Assign* ast; +}; + +struct CodeExpr_Alignof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Alignof ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Alignof* operator->(); + AST_Expr_Alignof* ast; +}; + +struct CodeExpr_Binary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Binary ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Binary* operator->(); + AST_Expr_Binary* ast; +}; + +struct CodeExpr_CStyleCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CStyleCast ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_CStyleCast* operator->(); + AST_Expr_CStyleCast* ast; +}; + +struct CodeExpr_FunctionalCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_FunctionalCast ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_FunctionalCast* operator->(); + AST_Expr_FunctionalCast* ast; +}; + +struct CodeExpr_CppCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_CppCast ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_CppCast* operator->(); + AST_Expr_CppCast* ast; +}; + +struct CodeExpr_Element +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Element ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Element* operator->(); + AST_Expr_Element* ast; +}; + +struct CodeExpr_ProcCall +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_ProcCall ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_ProcCall* operator->(); + AST_Expr_ProcCall* ast; +}; + +struct CodeExpr_Decltype +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Decltype ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Decltype* operator->(); + AST_Expr_Decltype* ast; +}; + +struct CodeExpr_Comma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Comma ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Comma* operator->(); + AST_Expr_Comma* ast; +}; + +struct CodeExpr_AMS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_AMS ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_AMS* operator->(); + AST_Expr_AMS* ast; +}; + +struct CodeExpr_Sizeof +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Sizeof ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Sizeof* operator->(); + AST_Expr_Sizeof* ast; +}; + +struct CodeExpr_Subscript +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Subscript ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Subscript* operator->(); + AST_Expr_Subscript* ast; +}; + +struct CodeExpr_Ternary +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_Ternary ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_Ternary* operator->(); + AST_Expr_Ternary* ast; +}; + +struct CodeExpr_UnaryPrefix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPrefix ); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Expr_UnaryPrefix* operator->(); + AST_Expr_UnaryPrefix* ast; +}; + +struct CodeExpr_UnaryPostfix +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExpr_UnaryPostfix ); + forceinline void to_string( String& result ); +#endif + AST* raw(); + operator Code(); + AST_Expr_UnaryPostfix* operator->(); + AST_Expr_UnaryPostfix* ast; +}; +#endif + +struct CodeExtern +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeExtern ); + forceinline void to_string( String& result ) { return extern_to_string(* this, & result); } +#endif + Using_CodeOps(CodeExtern); + operator Code(); + AST_Extern* operator->(); + AST_Extern* ast; +}; + +struct CodeInclude +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeInclude ); + String to_string() { return include_to_string(* this); } + forceinline void to_string( String& result ) { return include_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeInclude); + operator Code(); + AST_Include* operator->(); + AST_Include* ast; +}; + +struct CodeFriend +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFriend ); + forceinline String to_string() { return friend_to_string(* this); } + forceinline void to_string( String& result ) { return friend_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeFriend); + operator Code(); + AST_Friend* operator->(); + AST_Friend* ast; +}; + +struct CodeFn +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeFn ); + forceinline String to_string() { return fn_to_string(* this); } + forceinline void to_string_def( String& result ) { return fn_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return fn_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeFn); + operator Code(); + AST_Fn* operator->(); + AST_Fn* ast; +}; + +struct CodeModule +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeModule ); + forceinline String to_string() { return module_to_string(* this); } + forceinline void to_string( String& result ) { return module_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeModule); + operator Code(); + AST_Module* operator->(); + AST_Module* ast; +}; + +struct CodeNS +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeNS ); + forceinline String to_string() { return namespace_to_string(* this); } + forceinline void to_string( String& result ) { return namespace_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeNS); + operator Code(); + AST_NS* operator->(); + AST_NS* ast; +}; + +struct CodeOperator +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOperator ); + forceinline String to_string() { return code_op_to_string(* this); } + forceinline void to_string_def( String& result ) { return code_op_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return code_op_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOperator); + operator Code(); + AST_Operator* operator->(); + AST_Operator* ast; +}; + +struct CodeOpCast +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeOpCast ); + forceinline String to_string() { return opcast_to_string(* this); } + forceinline void to_string_def( String& result ) { return opcast_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return opcast_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeOpCast); + operator Code(); + AST_OpCast* operator->(); + AST_OpCast* ast; +}; + +struct CodePragma +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePragma ); + forceinline String to_string() { return pragma_to_string(* this); } + forceinline void to_string( String& result ) { return pragma_to_string_ref(* this, & result); } +#endif + Using_CodeOps( CodePragma ); + operator Code(); + AST_Pragma* operator->(); + AST_Pragma* ast; +}; + +struct CodePreprocessCond +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodePreprocessCond ); + forceinline String to_string() { return preprocess_to_string(* this); } + forceinline void to_string_if( String& result ) { return preprocess_to_string_if(* this, & result); } + forceinline void to_string_ifdef( String& result ) { return preprocess_to_string_ifdef(* this, & result); } + forceinline void to_string_ifndef( String& result ) { return preprocess_to_string_ifndef(* this, & result); } + forceinline void to_string_elif( String& result ) { return preprocess_to_string_elif(* this, & result); } + forceinline void to_string_else( String& result ) { return preprocess_to_string_else(* this, & result); } + forceinline void to_string_endif( String& result ) { return preprocess_to_string_endif(* this, & result); } +#endif + Using_CodeOps( CodePreprocessCond ); + operator Code(); + AST_PreprocessCond* operator->(); + AST_PreprocessCond* ast; +}; + +#if GEN_EXECUTION_EXPRESSION_SUPPORT +struct CodeStmt +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt* operator->(); + AST_Stmt* ast; +}; + +struct CodeStmt_Break +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Break ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Break* operator->(); + AST_Stmt_Break* ast; +}; + +struct CodeStmt_Case +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Case ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Case* operator->(); + AST_Stmt_Case* ast; +}; + +struct CodeStmt_Continue +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Continue ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Continue* operator->(); + AST_Stmt_Continue* ast; +}; + +struct CodeStmt_Decl +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Decl ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Decl* operator->(); + AST_Stmt_Decl* ast; +}; + +struct CodeStmt_Do +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Do ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Do* operator->(); + AST_Stmt_Do* ast; +}; + +struct CodeStmt_Expr +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Expr ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Expr* operator->(); + AST_Stmt_Expr* ast; +}; + +struct CodeStmt_Else +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Else ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Else* operator->(); + AST_Stmt_Else* ast; +}; + +struct CodeStmt_If +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_If ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_If* operator->(); + AST_Stmt_If* ast; +}; + +struct CodeStmt_For +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_For ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_For* operator->(); + AST_Stmt_For* ast; +}; + +struct CodeStmt_Goto +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Goto ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Goto* operator->(); + AST_Stmt_Goto* ast; +}; + +struct CodeStmt_Label +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Label ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Label* operator->(); + AST_Stmt_Label* ast; +}; + +struct CodeStmt_Switch +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_Switch ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_Switch* operator->(); + AST_Stmt_Switch* ast; +}; + +struct CodeStmt_While +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStmt_While ); + forceinline String to_string(); + forceinline void to_string( String& result ); +#endif + operator Code(); + AST_Stmt_While* operator->(); + AST_Stmt_While* ast; +}; +#endif + +struct CodeTemplate +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTemplate ); + forceinline String to_string() { return template_to_string(* this); } + forceinline void to_string( String& result ) { return template_to_string_ref(* this, & result); } +#endif + Using_CodeOps( CodeTemplate ); + operator Code(); + AST_Template* operator->(); + AST_Template* ast; +}; + +struct CodeTypename +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypename ); + forceinline String to_string() { return typename_to_string(* this); } + forceinline void to_string( String& result ) { return typename_to_string_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypename ); + operator Code(); + AST_Typename* operator->(); + AST_Typename* ast; +}; + +struct CodeTypedef +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeTypedef ); + forceinline String to_string() { return typedef_to_string(* this); } + forceinline void to_string( String& result ) { return typedef_to_string_ref(* this, & result); } +#endif + Using_CodeOps( CodeTypedef ); + operator Code(); + AST_Typedef* operator->(); + AST_Typedef* ast; +}; + +struct CodeUnion +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUnion ); + forceinline String to_string() { return union_to_string(* this); } + forceinline void to_string_def( String& result ) { return union_to_string_def(* this, & result); } + forceinline void to_string_fwd( String& result ) { return union_to_string_fwd(* this, & result); } +#endif + Using_CodeOps(CodeUnion); + operator Code(); + AST_Union* operator->(); + AST_Union* ast; +}; + +struct CodeUsing +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeUsing ); + forceinline String to_string() { return using_to_string(* this); } + forceinline void to_string( String& result ) { return using_to_string_ref(* this, & result); } + forceinline void to_string_ns( String& result ) { return using_to_string_ns(* this, & result); } +#endif + Using_CodeOps(CodeUsing); + operator Code(); + AST_Using* operator->(); + AST_Using* ast; +}; + +struct CodeVar +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeVar ); + forceinline String to_string() { return var_to_string(* this); } + forceinline void to_string( String& result ) { return var_to_string_ref(* this, & result); } +#endif + Using_CodeOps(CodeVar); + operator Code(); + AST_Var* operator->(); + AST_Var* ast; +}; + +struct CodeStruct +{ +#if ! GEN_C_LIKE_CPP + Using_Code( CodeStruct ); + forceinline void add_interface( CodeTypename interface ) { return struct_add_interface(* this, interface); } + forceinline String to_string() { return struct_to_string(* this); } + forceinline void to_string_fwd( String& result ) { return struct_to_string_fwd(* this, & result); } + forceinline void to_string_def( String& result ) { return struct_to_string_def(* this, & result); } +#endif + Using_CodeOps( CodeStruct ); + forceinline operator Code() { return * rcast( Code*, this ); } + forceinline AST_Struct* operator->() { + GEN_ASSERT(ast); + return ast; + } + AST_Struct* ast; +}; + +#undef Define_CodeType +#undef Using_Code +#undef Using_CodeOps + +#undef Verify_POD + +struct InvalidCode_ImplictCaster +{ + // operator CodeBaseClass() const; + operator Code () const { return Code_Invalid; } + operator CodeBody () const { return cast(CodeBody, Code_Invalid); } + operator CodeAttributes () const { return cast(CodeAttributes, Code_Invalid); } + operator CodeComment () const { return cast(CodeComment, Code_Invalid); } + operator CodeClass () const { return cast(CodeClass, Code_Invalid); } + operator CodeConstructor () const { return cast(CodeConstructor, Code_Invalid); } + operator CodeDefine () const { return cast(CodeDefine, Code_Invalid); } + operator CodeDestructor () const { return cast(CodeDestructor, Code_Invalid); } + operator CodeExec () const { return cast(CodeExec, Code_Invalid); } + operator CodeEnum () const { return cast(CodeEnum, Code_Invalid); } + operator CodeExtern () const { return cast(CodeExtern, Code_Invalid); } + operator CodeInclude () const { return cast(CodeInclude, Code_Invalid); } + operator CodeFriend () const { return cast(CodeFriend, Code_Invalid); } + operator CodeFn () const { return cast(CodeFn, Code_Invalid); } + operator CodeModule () const { return cast(CodeModule, Code_Invalid); } + operator CodeNS () const { return cast(CodeNS, Code_Invalid); } + operator CodeOperator () const { return cast(CodeOperator, Code_Invalid); } + operator CodeOpCast () const { return cast(CodeOpCast, Code_Invalid); } + operator CodeParams () const { return cast(CodeParams, Code_Invalid); } + operator CodePragma () const { return cast(CodePragma, Code_Invalid); } + operator CodePreprocessCond() const { return cast(CodePreprocessCond, Code_Invalid); } + operator CodeSpecifiers () const { return cast(CodeSpecifiers, Code_Invalid); } + operator CodeStruct () const { return cast(CodeStruct, Code_Invalid); } + operator CodeTemplate () const { return cast(CodeTemplate, Code_Invalid); } + operator CodeTypename () const { return cast(CodeTypename, Code_Invalid); } + operator CodeTypedef () const { return cast(CodeTypedef, Code_Invalid); } + operator CodeUnion () const { return cast(CodeUnion, Code_Invalid); } + operator CodeUsing () const { return cast(CodeUsing, Code_Invalid); } + operator CodeVar () const { return cast(CodeVar, Code_Invalid); } +}; + +struct NullCode_ImplicitCaster +{ + operator Code () const { return {nullptr}; } + operator CodeBody () const { return {(AST_Body*) nullptr}; } + operator CodeAttributes () const { return {(AST_Attributes*)nullptr}; } + operator CodeComment () const { return {nullptr}; } + operator CodeClass () const { return {nullptr}; } + operator CodeConstructor () const { return {nullptr}; } + operator CodeDefine () const { return {nullptr}; } + operator CodeDestructor () const { return {nullptr}; } + operator CodeExec () const { return {nullptr}; } + operator CodeEnum () const { return {nullptr}; } + operator CodeExtern () const { return {nullptr}; } + operator CodeInclude () const { return {nullptr}; } + operator CodeFriend () const { return {nullptr}; } + operator CodeFn () const { return {nullptr}; } + operator CodeModule () const { return {nullptr}; } + operator CodeNS () const { return {nullptr}; } + operator CodeOperator () const { return {nullptr}; } + operator CodeOpCast () const { return {nullptr}; } + operator CodeParams () const { return {nullptr}; } + operator CodePragma () const { return {nullptr}; } + operator CodePreprocessCond() const { return {nullptr}; } + operator CodeSpecifiers () const { return {nullptr}; } + operator CodeStruct () const { return {nullptr}; } + operator CodeTemplate () const { return {nullptr}; } + operator CodeTypename () const { return CodeTypename{(AST_Typename*)nullptr}; } + operator CodeTypedef () const { return {nullptr}; } + operator CodeUnion () const { return {nullptr}; } + operator CodeUsing () const { return {nullptr}; } + operator CodeVar () const { return {nullptr}; } +}; + +#if ! GEN_C_LIKE_CPP +GEN_OPTIMIZE_MAPPINGS_BEGIN + +forceinline void append ( CodeBody body, Code other ) { return body_append(body, other); } +forceinline void append ( CodeBody body, CodeBody other ) { return body_append_body(body, other); } +forceinline String to_string ( CodeBody body ) { return body_to_string(body); } +forceinline void to_string ( CodeBody body, String& result ) { return body_to_string_ref(body, & result); } +forceinline void to_string_export( CodeBody body, String& result ) { return body_to_string_export(body, & result); } + +forceinline Code begin( CodeBody body) { return begin_CodeBody(body); } +forceinline Code end ( CodeBody body ) { return end_CodeBody(body); } +forceinline Code next ( CodeBody body, Code entry_iter ) { return next_CodeBody(body, entry_iter); } + +forceinline void add_interface( CodeClass self, CodeTypename interface ) { return class_add_interface(self, interface); } +forceinline String to_string ( CodeClass self ) { return class_to_string(self); } +forceinline void to_string_def( CodeClass self, String& result ) { return class_to_string_def(self, & result); } +forceinline void to_string_fwd( CodeClass self, String& result ) { return class_to_string_fwd(self, & result); } + +forceinline void append (CodeParams params, CodeParams param ) { return params_append(params, param); } +forceinline CodeParams get (CodeParams params, s32 idx) { return params_get(params, idx); } +forceinline bool has_entries(CodeParams params ) { return params_has_entries(params); } +forceinline String to_string (CodeParams params ) { return params_to_string(params); } +forceinline void to_string (CodeParams params, String& result ) { return params_to_string_ref(params, & result); } + +forceinline CodeParams begin(CodeParams params) { return begin_CodeParams(params); } +forceinline CodeParams end (CodeParams params) { return end_CodeParams(params); } +forceinline CodeParams next (CodeParams params, CodeParams entry_iter) { return next_CodeParams(params, entry_iter); } + +forceinline bool append (CodeSpecifiers specifiers, Specifier spec) { return specifiers_append(specifiers, spec); } +forceinline s32 has (CodeSpecifiers specifiers, Specifier spec) { return specifiers_has(specifiers, spec); } +forceinline s32 remove (CodeSpecifiers specifiers, Specifier to_remove ) { return specifiers_remove(specifiers, to_remove); } +forceinline String to_string(CodeSpecifiers specifiers) { return specifiers_to_string(specifiers); } +forceinline void to_string(CodeSpecifiers specifiers, String& result) { return specifiers_to_string_ref(specifiers, & result); } + +forceinline Specifier* begin(CodeSpecifiers specifiers) { return begin_CodeSpecifiers(specifiers); } +forceinline Specifier* end (CodeSpecifiers specifiers) { return end_CodeSpecifiers(specifiers); } +forceinline Specifier* next (CodeSpecifiers specifiers, Specifier& spec_iter) { return next_CodeSpecifiers(specifiers, & spec_iter); } + +forceinline void add_interface(CodeStruct self, CodeTypename interface) { return struct_add_interface(self, interface); } +forceinline String to_string (CodeStruct self) { return struct_to_string(self); } +forceinline void to_string_fwd(CodeStruct self, String& result) { return struct_to_string_fwd(self, & result); } +forceinline void to_string_def(CodeStruct self, String& result) { return struct_to_string_def(self, & result); } + +forceinline String to_string(CodeAttributes attributes) { return attributes_to_string(attributes); } +forceinline void to_string(CodeAttributes attributes, String& result) { return attributes_to_string_ref(attributes, & result); } + +forceinline String to_string(CodeComment comment ) { return comment_to_string(comment); } +forceinline void to_string(CodeComment comment, String& result ) { return comment_to_string_ref(comment, & result); } + +forceinline String to_string (CodeConstructor constructor) { return constructor_to_string(constructor); } +forceinline void to_string_def(CodeConstructor constructor, String& result ) { return constructor_to_string_def(constructor, & result); } +forceinline void to_string_fwd(CodeConstructor constructor, String& result ) { return constructor_to_string_fwd(constructor, & result); } + +forceinline String to_string(CodeDefine self) { return define_to_string(self); } +forceinline void to_string(CodeDefine self, String& result) { return define_to_string_ref(self, & result); } + +forceinline String to_string (CodeDestructor destructor) { return destructor_to_string(destructor); } +forceinline void to_string_def(CodeDestructor destructor, String& result ) { return destructor_to_string_def(destructor, & result); } +forceinline void to_string_fwd(CodeDestructor destructor, String& result ) { return destructor_to_string_fwd(destructor, & result); } + +forceinline String to_string (CodeEnum self) { return enum_to_string(self); } +forceinline void to_string_def (CodeEnum self, String& result ) { return enum_to_string_def(self, & result); } +forceinline void to_string_fwd (CodeEnum self, String& result ) { return enum_to_string_fwd(self, & result); } +forceinline void to_string_class_def(CodeEnum self, String& result ) { return enum_to_string_class_def(self, & result); } +forceinline void to_string_class_fwd(CodeEnum self, String& result ) { return enum_to_string_class_fwd(self, & result); } + +forceinline String to_string(CodeExec exec) { return exec_to_string(exec); } +forceinline void to_string(CodeExec exec, String& result) { return exec_to_string_ref(exec, & result); } + +forceinline void to_string(CodeExtern self, String& result) { return extern_to_string(self, & result); } + +forceinline String to_string(CodeInclude self) { return include_to_string(self); } +forceinline void to_string(CodeInclude self, String& result) { return include_to_string_ref(self, & result); } + +forceinline String to_string(CodeFriend self) { return friend_to_string(self); } +forceinline void to_string(CodeFriend self, String& result) { return friend_to_string_ref(self, & result); } + +forceinline String to_string (CodeFn self) { return fn_to_string(self); } +forceinline void to_string_def(CodeFn self, String& result) { return fn_to_string_def(self, & result); } +forceinline void to_string_fwd(CodeFn self, String& result) { return fn_to_string_fwd(self, & result); } + +forceinline String to_string(CodeModule self) { return module_to_string(self); } +forceinline void to_string(CodeModule self, String& result) { return module_to_string_ref(self, & result); } + +forceinline String to_string(CodeNS self) { return namespace_to_string(self); } +forceinline void to_string(CodeNS self, String& result) { return namespace_to_string_ref(self, & result); } + +forceinline String to_string (CodeOperator self) { return code_op_to_string(self); } +forceinline void to_string_fwd(CodeOperator self, String& result ) { return code_op_to_string_fwd(self, & result); } +forceinline void to_string_def(CodeOperator self, String& result ) { return code_op_to_string_def(self, & result); } + +forceinline String to_string (CodeOpCast op_cast ) { return opcast_to_string(op_cast); } +forceinline void to_string_def(CodeOpCast op_cast, String& result ) { return opcast_to_string_def(op_cast, & result); } +forceinline void to_string_fwd(CodeOpCast op_cast, String& result ) { return opcast_to_string_fwd(op_cast, & result); } + +forceinline String to_string(CodePragma self) { return pragma_to_string(self); } +forceinline void to_string(CodePragma self, String& result) { return pragma_to_string_ref(self, & result); } + +forceinline String to_string (CodePreprocessCond cond) { return preprocess_to_string(cond); } +forceinline void to_string_if (CodePreprocessCond cond, String& result ) { return preprocess_to_string_if(cond, & result); } +forceinline void to_string_ifdef (CodePreprocessCond cond, String& result ) { return preprocess_to_string_ifdef(cond, & result); } +forceinline void to_string_ifndef(CodePreprocessCond cond, String& result ) { return preprocess_to_string_ifndef(cond, & result); } +forceinline void to_string_elif (CodePreprocessCond cond, String& result ) { return preprocess_to_string_elif(cond, & result); } +forceinline void to_string_else (CodePreprocessCond cond, String& result ) { return preprocess_to_string_else(cond, & result); } +forceinline void to_string_endif (CodePreprocessCond cond, String& result ) { return preprocess_to_string_endif(cond, & result); } + +forceinline String to_string(CodeTemplate self) { return template_to_string(self); } +forceinline void to_string(CodeTemplate self, String& result) { return template_to_string_ref(self, & result); } + +forceinline String to_string(CodeTypename self) { return typename_to_string(self); } +forceinline void to_string(CodeTypename self, String& result) { return typename_to_string_ref(self, & result); } + +forceinline String to_string(CodeTypedef self) { return typedef_to_string(self); } +forceinline void to_string(CodeTypedef self, String& result ) { return typedef_to_string_ref(self, & result); } + +forceinline String to_string (CodeUnion self) { return union_to_string(self); } +forceinline void to_string_def(CodeUnion self, String& result) { return union_to_string_def(self, & result); } +forceinline void to_string_fwd(CodeUnion self, String& result) { return union_to_string_fwd(self, & result); } + +forceinline String to_string (CodeUsing op_cast ) { return using_to_string(op_cast); } +forceinline void to_string (CodeUsing op_cast, String& result ) { return using_to_string_ref(op_cast, & result); } +forceinline void to_string_ns(CodeUsing op_cast, String& result ) { return using_to_string_ns(op_cast, & result); } + +forceinline String to_string(CodeVar self) { return var_to_string(self); } +forceinline void to_string(CodeVar self, String& result) { return var_to_string_ref(self, & result); } + +GEN_OPITMIZE_MAPPINGS_END +#endif //if GEN_C_LIKE_CPP + +#pragma endregion Code Types C++ +#endif //if GEN_COMPILER_CPP diff --git a/base/components/gen/ast_inlines.hpp b/base/components/gen/ast_inlines.hpp new file mode 100644 index 0000000..148e477 --- /dev/null +++ b/base/components/gen/ast_inlines.hpp @@ -0,0 +1,965 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "components/types.hpp" +#endif + +// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +#pragma region generated code inline implementation + +inline Code& Code::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline Code::operator bool() +{ + return ast != nullptr; +} + +inline CodeBody& CodeBody::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeBody::operator bool() +{ + return ast != nullptr; +} + +inline CodeAttributes& CodeAttributes::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeAttributes::operator bool() +{ + return ast != nullptr; +} + +inline CodeAttributes::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Attributes* CodeAttributes::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeComment& CodeComment::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeComment::operator bool() +{ + return ast != nullptr; +} + +inline CodeComment::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Comment* CodeComment::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeConstructor& CodeConstructor::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeConstructor::operator bool() +{ + return ast != nullptr; +} + +inline CodeConstructor::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Constructor* CodeConstructor::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeClass& CodeClass::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeClass::operator bool() +{ + return ast != nullptr; +} + +inline CodeDefine& CodeDefine::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeDefine::operator bool() +{ + return ast != nullptr; +} + +inline CodeDefine::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Define* CodeDefine::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeDestructor& CodeDestructor::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeDestructor::operator bool() +{ + return ast != nullptr; +} + +inline CodeDestructor::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Destructor* CodeDestructor::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeEnum& CodeEnum::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeEnum::operator bool() +{ + return ast != nullptr; +} + +inline CodeEnum::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Enum* CodeEnum::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeExec& CodeExec::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeExec::operator bool() +{ + return ast != nullptr; +} + +inline CodeExec::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Exec* CodeExec::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeExtern& CodeExtern::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeExtern::operator bool() +{ + return ast != nullptr; +} + +inline CodeExtern::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Extern* CodeExtern::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeFriend& CodeFriend::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeFriend::operator bool() +{ + return ast != nullptr; +} + +inline CodeFriend::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Friend* CodeFriend::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeFn& CodeFn::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeFn::operator bool() +{ + return ast != nullptr; +} + +inline CodeFn::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Fn* CodeFn::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeInclude& CodeInclude::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeInclude::operator bool() +{ + return ast != nullptr; +} + +inline CodeInclude::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Include* CodeInclude::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeModule& CodeModule::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeModule::operator bool() +{ + return ast != nullptr; +} + +inline CodeModule::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Module* CodeModule::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeNS& CodeNS::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeNS::operator bool() +{ + return ast != nullptr; +} + +inline CodeNS::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_NS* CodeNS::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeOperator& CodeOperator::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeOperator::operator bool() +{ + return ast != nullptr; +} + +inline CodeOperator::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Operator* CodeOperator::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeOpCast& CodeOpCast::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeOpCast::operator bool() +{ + return ast != nullptr; +} + +inline CodeOpCast::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_OpCast* CodeOpCast::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeParams& CodeParams::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeParams::operator bool() +{ + return ast != nullptr; +} + +inline CodePragma& CodePragma::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodePragma::operator bool() +{ + return ast != nullptr; +} + +inline CodePragma::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Pragma* CodePragma::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodePreprocessCond& CodePreprocessCond::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodePreprocessCond::operator bool() +{ + return ast != nullptr; +} + +inline CodePreprocessCond::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_PreprocessCond* CodePreprocessCond::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeSpecifiers& CodeSpecifiers::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeSpecifiers::operator bool() +{ + return ast != nullptr; +} + +inline CodeStruct& CodeStruct::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeStruct::operator bool() +{ + return ast != nullptr; +} + +inline CodeTemplate& CodeTemplate::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeTemplate::operator bool() +{ + return ast != nullptr; +} + +inline CodeTemplate::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Template* CodeTemplate::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeTypename& CodeTypename::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeTypename::operator bool() +{ + return ast != nullptr; +} + +inline CodeTypename::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Typename* CodeTypename::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeTypedef& CodeTypedef::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeTypedef::operator bool() +{ + return ast != nullptr; +} + +inline CodeTypedef::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Typedef* CodeTypedef::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeUnion& CodeUnion::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeUnion::operator bool() +{ + return ast != nullptr; +} + +inline CodeUnion::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Union* CodeUnion::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeUsing& CodeUsing::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeUsing::operator bool() +{ + return ast != nullptr; +} + +inline CodeUsing::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Using* CodeUsing::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +inline CodeVar& CodeVar::operator=( Code other ) +{ + if ( other.ast != nullptr && other->Parent != nullptr ) + { + ast = rcast( decltype( ast ), code_duplicate( other ).ast ); + ast->Parent = { nullptr }; + } + ast = rcast( decltype( ast ), other.ast ); + return *this; +} + +inline CodeVar::operator bool() +{ + return ast != nullptr; +} + +inline CodeVar::operator Code() +{ + return *rcast( Code*, this ); +} + +inline AST_Var* CodeVar::operator->() +{ + if ( ast == nullptr ) + { + log_failure( "Attempt to dereference a nullptr!" ); + return nullptr; + } + return ast; +} + +#pragma endregion generated code inline implementation + +#pragma region generated AST/Code cast implementation +GEN_OPTIMIZE_MAPPINGS_BEGIN + +forceinline Code::operator CodeBody() const +{ + return { (AST_Body*)ast }; +} + +forceinline Code::operator CodeAttributes() const +{ + return { (AST_Attributes*)ast }; +} + +forceinline Code::operator CodeComment() const +{ + return { (AST_Comment*)ast }; +} + +forceinline Code::operator CodeConstructor() const +{ + return { (AST_Constructor*)ast }; +} + +forceinline Code::operator CodeClass() const +{ + return { (AST_Class*)ast }; +} + +forceinline Code::operator CodeDefine() const +{ + return { (AST_Define*)ast }; +} + +forceinline Code::operator CodeDestructor() const +{ + return { (AST_Destructor*)ast }; +} + +forceinline Code::operator CodeEnum() const +{ + return { (AST_Enum*)ast }; +} + +forceinline Code::operator CodeExec() const +{ + return { (AST_Exec*)ast }; +} + +forceinline Code::operator CodeExtern() const +{ + return { (AST_Extern*)ast }; +} + +forceinline Code::operator CodeFriend() const +{ + return { (AST_Friend*)ast }; +} + +forceinline Code::operator CodeFn() const +{ + return { (AST_Fn*)ast }; +} + +forceinline Code::operator CodeInclude() const +{ + return { (AST_Include*)ast }; +} + +forceinline Code::operator CodeModule() const +{ + return { (AST_Module*)ast }; +} + +forceinline Code::operator CodeNS() const +{ + return { (AST_NS*)ast }; +} + +forceinline Code::operator CodeOperator() const +{ + return { (AST_Operator*)ast }; +} + +forceinline Code::operator CodeOpCast() const +{ + return { (AST_OpCast*)ast }; +} + +forceinline Code::operator CodeParams() const +{ + return { (AST_Params*)ast }; +} + +forceinline Code::operator CodePragma() const +{ + return { (AST_Pragma*)ast }; +} + +forceinline Code::operator CodePreprocessCond() const +{ + return { (AST_PreprocessCond*)ast }; +} + +forceinline Code::operator CodeSpecifiers() const +{ + return { (AST_Specifiers*)ast }; +} + +forceinline Code::operator CodeStruct() const +{ + return { (AST_Struct*)ast }; +} + +forceinline Code::operator CodeTemplate() const +{ + return { (AST_Template*)ast }; +} + +forceinline Code::operator CodeTypename() const +{ + return { (AST_Typename*)ast }; +} + +forceinline Code::operator CodeTypedef() const +{ + return { (AST_Typedef*)ast }; +} + +forceinline Code::operator CodeUnion() const +{ + return { (AST_Union*)ast }; +} + +forceinline Code::operator CodeUsing() const +{ + return { (AST_Using*)ast }; +} + +forceinline Code::operator CodeVar() const +{ + return { (AST_Var*)ast }; +} + +GEN_OPITMIZE_MAPPINGS_END +#pragma endregion generated AST / Code cast implementation diff --git a/base/components/gen/ecodetypes.hpp b/base/components/gen/ecodetypes.hpp new file mode 100644 index 0000000..7321695 --- /dev/null +++ b/base/components/gen/ecodetypes.hpp @@ -0,0 +1,219 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "components/types.hpp" +#endif + +// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +enum CodeType : u32 +{ + CT_Invalid, + CT_Untyped, + CT_NewLine, + CT_Comment, + CT_Access_Private, + CT_Access_Protected, + CT_Access_Public, + CT_PlatformAttributes, + CT_Class, + CT_Class_Fwd, + CT_Class_Body, + CT_Constructor, + CT_Constructor_Fwd, + CT_Destructor, + CT_Destructor_Fwd, + CT_Enum, + CT_Enum_Fwd, + CT_Enum_Body, + CT_Enum_Class, + CT_Enum_Class_Fwd, + CT_Execution, + CT_Export_Body, + CT_Extern_Linkage, + CT_Extern_Linkage_Body, + CT_Friend, + CT_Function, + CT_Function_Fwd, + CT_Function_Body, + CT_Global_Body, + CT_Module, + CT_Namespace, + CT_Namespace_Body, + CT_Operator, + CT_Operator_Fwd, + CT_Operator_Member, + CT_Operator_Member_Fwd, + CT_Operator_Cast, + CT_Operator_Cast_Fwd, + CT_Parameters, + CT_Preprocess_Define, + CT_Preprocess_Include, + CT_Preprocess_If, + CT_Preprocess_IfDef, + CT_Preprocess_IfNotDef, + CT_Preprocess_ElIf, + CT_Preprocess_Else, + CT_Preprocess_EndIf, + CT_Preprocess_Pragma, + CT_Specifiers, + CT_Struct, + CT_Struct_Fwd, + CT_Struct_Body, + CT_Template, + CT_Typedef, + CT_Typename, + CT_Union, + CT_Union_Fwd, + CT_Union_Body, + CT_Using, + CT_Using_Namespace, + CT_Variable, + CT_NumTypes, + CT_UnderlyingType = GEN_U32_MAX +}; + +inline StrC codetype_to_str( CodeType type ) +{ + local_persist StrC lookup[61] = { + { sizeof( "Invalid" ), "Invalid" }, + { sizeof( "Untyped" ), "Untyped" }, + { sizeof( "NewLine" ), "NewLine" }, + { sizeof( "Comment" ), "Comment" }, + { sizeof( "Access_Private" ), "Access_Private" }, + { sizeof( "Access_Protected" ), "Access_Protected" }, + { sizeof( "Access_Public" ), "Access_Public" }, + { sizeof( "PlatformAttributes" ), "PlatformAttributes" }, + { sizeof( "Class" ), "Class" }, + { sizeof( "Class_Fwd" ), "Class_Fwd" }, + { sizeof( "Class_Body" ), "Class_Body" }, + { sizeof( "Constructor" ), "Constructor" }, + { sizeof( "Constructor_Fwd" ), "Constructor_Fwd" }, + { sizeof( "Destructor" ), "Destructor" }, + { sizeof( "Destructor_Fwd" ), "Destructor_Fwd" }, + { sizeof( "Enum" ), "Enum" }, + { sizeof( "Enum_Fwd" ), "Enum_Fwd" }, + { sizeof( "Enum_Body" ), "Enum_Body" }, + { sizeof( "Enum_Class" ), "Enum_Class" }, + { sizeof( "Enum_Class_Fwd" ), "Enum_Class_Fwd" }, + { sizeof( "Execution" ), "Execution" }, + { sizeof( "Export_Body" ), "Export_Body" }, + { sizeof( "Extern_Linkage" ), "Extern_Linkage" }, + { sizeof( "Extern_Linkage_Body" ), "Extern_Linkage_Body" }, + { sizeof( "Friend" ), "Friend" }, + { sizeof( "Function" ), "Function" }, + { sizeof( "Function_Fwd" ), "Function_Fwd" }, + { sizeof( "Function_Body" ), "Function_Body" }, + { sizeof( "Global_Body" ), "Global_Body" }, + { sizeof( "Module" ), "Module" }, + { sizeof( "Namespace" ), "Namespace" }, + { sizeof( "Namespace_Body" ), "Namespace_Body" }, + { sizeof( "Operator" ), "Operator" }, + { sizeof( "Operator_Fwd" ), "Operator_Fwd" }, + { sizeof( "Operator_Member" ), "Operator_Member" }, + { sizeof( "Operator_Member_Fwd" ), "Operator_Member_Fwd" }, + { sizeof( "Operator_Cast" ), "Operator_Cast" }, + { sizeof( "Operator_Cast_Fwd" ), "Operator_Cast_Fwd" }, + { sizeof( "Parameters" ), "Parameters" }, + { sizeof( "Preprocess_Define" ), "Preprocess_Define" }, + { sizeof( "Preprocess_Include" ), "Preprocess_Include" }, + { sizeof( "Preprocess_If" ), "Preprocess_If" }, + { sizeof( "Preprocess_IfDef" ), "Preprocess_IfDef" }, + { sizeof( "Preprocess_IfNotDef" ), "Preprocess_IfNotDef" }, + { sizeof( "Preprocess_ElIf" ), "Preprocess_ElIf" }, + { sizeof( "Preprocess_Else" ), "Preprocess_Else" }, + { sizeof( "Preprocess_EndIf" ), "Preprocess_EndIf" }, + { sizeof( "Preprocess_Pragma" ), "Preprocess_Pragma" }, + { sizeof( "Specifiers" ), "Specifiers" }, + { sizeof( "Struct" ), "Struct" }, + { sizeof( "Struct_Fwd" ), "Struct_Fwd" }, + { sizeof( "Struct_Body" ), "Struct_Body" }, + { sizeof( "Template" ), "Template" }, + { sizeof( "Typedef" ), "Typedef" }, + { sizeof( "Typename" ), "Typename" }, + { sizeof( "Union" ), "Union" }, + { sizeof( "Union_Fwd" ), "Union_Fwd" }, + { sizeof( "Union_Body" ), "Union_Body" }, + { sizeof( "Using" ), "Using" }, + { sizeof( "Using_Namespace" ), "Using_Namespace" }, + { sizeof( "Variable" ), "Variable" }, + }; + return lookup[type]; +} + +inline StrC codetype_to_keyword_str( CodeType type ) +{ + local_persist StrC lookup[61] = { + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "//" ) - 1, "//" }, + { sizeof( "private" ) - 1, "private" }, + { sizeof( "protected" ) - 1, "protected" }, + { sizeof( "public" ) - 1, "public" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "class" ) - 1, "class" }, + { sizeof( "clsss" ) - 1, "clsss" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "enum" ) - 1, "enum" }, + { sizeof( "enum" ) - 1, "enum" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "enum class" ) - 1, "enum class" }, + { sizeof( "enum class" ) - 1, "enum class" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "extern" ) - 1, "extern" }, + { sizeof( "extern" ) - 1, "extern" }, + { sizeof( "friend" ) - 1, "friend" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "module" ) - 1, "module" }, + { sizeof( "namespace" ) - 1, "namespace" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "operator" ) - 1, "operator" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "define" ) - 1, "define" }, + { sizeof( "include" ) - 1, "include" }, + { sizeof( "if" ) - 1, "if" }, + { sizeof( "ifdef" ) - 1, "ifdef" }, + { sizeof( "ifndef" ) - 1, "ifndef" }, + { sizeof( "elif" ) - 1, "elif" }, + { sizeof( "else" ) - 1, "else" }, + { sizeof( "endif" ) - 1, "endif" }, + { sizeof( "pragma" ) - 1, "pragma" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "struct" ) - 1, "struct" }, + { sizeof( "struct" ) - 1, "struct" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "template" ) - 1, "template" }, + { sizeof( "typedef" ) - 1, "typedef" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "union" ) - 1, "union" }, + { sizeof( "union" ) - 1, "union" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + { sizeof( "using" ) - 1, "using" }, + { sizeof( "using namespace" ) - 1, "using namespace" }, + { sizeof( "__NA__" ) - 1, "__NA__" }, + }; + return lookup[type]; +} + +forceinline StrC to_str( CodeType type ) +{ + return codetype_to_str( type ); +} + +forceinline StrC to_keyword_str( CodeType type ) +{ + return codetype_to_keyword_str( type ); +} diff --git a/base/components/gen/eoperator.hpp b/base/components/gen/eoperator.hpp new file mode 100644 index 0000000..f45e441 --- /dev/null +++ b/base/components/gen/eoperator.hpp @@ -0,0 +1,118 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "components/types.hpp" +#endif + +// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +enum Operator : u32 +{ + Op_Invalid, + Op_Assign, + Op_Assign_Add, + Op_Assign_Subtract, + Op_Assign_Multiply, + Op_Assign_Divide, + Op_Assign_Modulo, + Op_Assign_BAnd, + Op_Assign_BOr, + Op_Assign_BXOr, + Op_Assign_LShift, + Op_Assign_RShift, + Op_Increment, + Op_Decrement, + Op_Unary_Plus, + Op_Unary_Minus, + Op_UnaryNot, + Op_Add, + Op_Subtract, + Op_Multiply, + Op_Divide, + Op_Modulo, + Op_BNot, + Op_BAnd, + Op_BOr, + Op_BXOr, + Op_LShift, + Op_RShift, + Op_LAnd, + Op_LOr, + Op_LEqual, + Op_LNot, + Op_Lesser, + Op_Greater, + Op_LesserEqual, + Op_GreaterEqual, + Op_Subscript, + Op_Indirection, + Op_AddressOf, + Op_MemberOfPointer, + Op_PtrToMemOfPtr, + Op_FunctionCall, + Op_Comma, + Op_New, + Op_NewArray, + Op_Delete, + Op_DeleteArray, + Op_NumOps, + Op_UnderlyingType = 0xffffffffu +}; + +inline StrC operator_to_str( Operator op ) +{ + local_persist StrC lookup[47] = { + { sizeof( "INVALID" ), "INVALID" }, + { sizeof( "=" ), "=" }, + { sizeof( "+=" ), "+=" }, + { sizeof( "-=" ), "-=" }, + { sizeof( "*=" ), "*=" }, + { sizeof( "/=" ), "/=" }, + { sizeof( "%=" ), "%=" }, + { sizeof( "&=" ), "&=" }, + { sizeof( "|=" ), "|=" }, + { sizeof( "^=" ), "^=" }, + { sizeof( "<<=" ), "<<=" }, + { sizeof( ">>=" ), ">>=" }, + { sizeof( "++" ), "++" }, + { sizeof( "--" ), "--" }, + { sizeof( "+" ), "+" }, + { sizeof( "-" ), "-" }, + { sizeof( "!" ), "!" }, + { sizeof( "+" ), "+" }, + { sizeof( "-" ), "-" }, + { sizeof( "*" ), "*" }, + { sizeof( "/" ), "/" }, + { sizeof( "%" ), "%" }, + { sizeof( "~" ), "~" }, + { sizeof( "&" ), "&" }, + { sizeof( "|" ), "|" }, + { sizeof( "^" ), "^" }, + { sizeof( "<<" ), "<<" }, + { sizeof( ">>" ), ">>" }, + { sizeof( "&&" ), "&&" }, + { sizeof( "||" ), "||" }, + { sizeof( "==" ), "==" }, + { sizeof( "!=" ), "!=" }, + { sizeof( "<" ), "<" }, + { sizeof( ">" ), ">" }, + { sizeof( "<=" ), "<=" }, + { sizeof( ">=" ), ">=" }, + { sizeof( "[]" ), "[]" }, + { sizeof( "*" ), "*" }, + { sizeof( "&" ), "&" }, + { sizeof( "->" ), "->" }, + { sizeof( "->*" ), "->*" }, + { sizeof( "()" ), "()" }, + { sizeof( "," ), "," }, + { sizeof( "new" ), "new" }, + { sizeof( "new[]" ), "new[]" }, + { sizeof( "delete" ), "delete" }, + { sizeof( "delete[]" ), "delete[]" }, + }; + return lookup[op]; +} + +forceinline StrC to_str( Operator op ) +{ + return operator_to_str( op ); +} diff --git a/base/components/gen/especifier.hpp b/base/components/gen/especifier.hpp new file mode 100644 index 0000000..6298888 --- /dev/null +++ b/base/components/gen/especifier.hpp @@ -0,0 +1,108 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "components/types.hpp" +#endif + +// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +enum Specifier : u32 +{ + Spec_Invalid, + Spec_Consteval, + Spec_Constexpr, + Spec_Constinit, + Spec_Explicit, + Spec_External_Linkage, + Spec_ForceInline, + Spec_Global, + Spec_Inline, + Spec_Internal_Linkage, + Spec_Local_Persist, + Spec_Mutable, + Spec_NeverInline, + Spec_Ptr, + Spec_Ref, + Spec_Register, + Spec_RValue, + Spec_Static, + Spec_Thread_Local, + Spec_Virtual, + Spec_Const, + Spec_Final, + Spec_NoExceptions, + Spec_Override, + Spec_Pure, + Spec_Volatile, + Spec_NumSpecifiers, + Spec_UnderlyingType = 0xffffffffu +}; + +inline StrC spec_to_str( Specifier type ) +{ + local_persist StrC lookup[26] = { + { sizeof( "INVALID" ), "INVALID" }, + { sizeof( "consteval" ), "consteval" }, + { sizeof( "constexpr" ), "constexpr" }, + { sizeof( "constinit" ), "constinit" }, + { sizeof( "explicit" ), "explicit" }, + { sizeof( "extern" ), "extern" }, + { sizeof( "forceinline" ), "forceinline" }, + { sizeof( "global" ), "global" }, + { sizeof( "inline" ), "inline" }, + { sizeof( "internal" ), "internal" }, + { sizeof( "local_persist" ), "local_persist" }, + { sizeof( "mutable" ), "mutable" }, + { sizeof( "neverinline" ), "neverinline" }, + { sizeof( "*" ), "*" }, + { sizeof( "&" ), "&" }, + { sizeof( "register" ), "register" }, + { sizeof( "&&" ), "&&" }, + { sizeof( "static" ), "static" }, + { sizeof( "thread_local" ), "thread_local" }, + { sizeof( "virtual" ), "virtual" }, + { sizeof( "const" ), "const" }, + { sizeof( "final" ), "final" }, + { sizeof( "noexcept" ), "noexcept" }, + { sizeof( "override" ), "override" }, + { sizeof( "= 0" ), "= 0" }, + { sizeof( "volatile" ), "volatile" }, + }; + return lookup[type]; +} + +inline bool spec_is_trailing( Specifier specifier ) +{ + return specifier > Spec_Virtual; +} + +inline Specifier strc_to_specifier( StrC str ) +{ + local_persist u32 keymap[Spec_NumSpecifiers]; + do_once_start for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) + { + StrC enum_str = spec_to_str( (Specifier)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); + } + do_once_end u32 hash = crc32( str.Ptr, str.Len ); + for ( u32 index = 0; index < Spec_NumSpecifiers; index++ ) + { + if ( keymap[index] == hash ) + return (Specifier)index; + } + return Spec_Invalid; +} + +forceinline StrC to_str( Specifier spec ) +{ + return spec_to_str( spec ); +} + +forceinline Specifier to_type( StrC str ) +{ + return strc_to_specifier( str ); +} + +forceinline bool is_trailing( Specifier specifier ) +{ + return spec_is_trailing( specifier ); +} diff --git a/base/components/gen/etoktype.cpp b/base/components/gen/etoktype.cpp new file mode 100644 index 0000000..574f516 --- /dev/null +++ b/base/components/gen/etoktype.cpp @@ -0,0 +1,235 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "components/types.hpp" +#endif + +// This file was generated automatially by gencpp's bootstrap.cpp (See: https://github.com/Ed94/gencpp) + +GEN_NS_PARSER_BEGIN + +#define GEN_DEFINE_ATTRIBUTE_TOKENS Entry( Tok_Attribute_API_Export, "GEN_API_Export_Code" ) Entry( Tok_Attribute_API_Import, "GEN_API_Import_Code" ) + +enum TokType : u32 +{ + Tok_Invalid, + Tok_Access_Private, + Tok_Access_Protected, + Tok_Access_Public, + Tok_Access_MemberSymbol, + Tok_Access_StaticSymbol, + Tok_Ampersand, + Tok_Ampersand_DBL, + Tok_Assign_Classifer, + Tok_Attribute_Open, + Tok_Attribute_Close, + Tok_BraceCurly_Open, + Tok_BraceCurly_Close, + Tok_BraceSquare_Open, + Tok_BraceSquare_Close, + Tok_Capture_Start, + Tok_Capture_End, + Tok_Comment, + Tok_Comment_End, + Tok_Comment_Start, + Tok_Char, + Tok_Comma, + Tok_Decl_Class, + Tok_Decl_GNU_Attribute, + Tok_Decl_MSVC_Attribute, + Tok_Decl_Enum, + Tok_Decl_Extern_Linkage, + Tok_Decl_Friend, + Tok_Decl_Module, + Tok_Decl_Namespace, + Tok_Decl_Operator, + Tok_Decl_Struct, + Tok_Decl_Template, + Tok_Decl_Typedef, + Tok_Decl_Using, + Tok_Decl_Union, + Tok_Identifier, + Tok_Module_Import, + Tok_Module_Export, + Tok_NewLine, + Tok_Number, + Tok_Operator, + Tok_Preprocess_Hash, + Tok_Preprocess_Define, + Tok_Preprocess_If, + Tok_Preprocess_IfDef, + Tok_Preprocess_IfNotDef, + Tok_Preprocess_ElIf, + Tok_Preprocess_Else, + Tok_Preprocess_EndIf, + Tok_Preprocess_Include, + Tok_Preprocess_Pragma, + Tok_Preprocess_Content, + Tok_Preprocess_Macro, + Tok_Preprocess_Unsupported, + Tok_Spec_Alignas, + Tok_Spec_Const, + Tok_Spec_Consteval, + Tok_Spec_Constexpr, + Tok_Spec_Constinit, + Tok_Spec_Explicit, + Tok_Spec_Extern, + Tok_Spec_Final, + Tok_Spec_ForceInline, + Tok_Spec_Global, + Tok_Spec_Inline, + Tok_Spec_Internal_Linkage, + Tok_Spec_LocalPersist, + Tok_Spec_Mutable, + Tok_Spec_NeverInline, + Tok_Spec_Override, + Tok_Spec_Static, + Tok_Spec_ThreadLocal, + Tok_Spec_Volatile, + Tok_Spec_Virtual, + Tok_Star, + Tok_Statement_End, + Tok_StaticAssert, + Tok_String, + Tok_Type_Typename, + Tok_Type_Unsigned, + Tok_Type_Signed, + Tok_Type_Short, + Tok_Type_Long, + Tok_Type_bool, + Tok_Type_char, + Tok_Type_int, + Tok_Type_double, + Tok_Type_MS_int8, + Tok_Type_MS_int16, + Tok_Type_MS_int32, + Tok_Type_MS_int64, + Tok_Type_MS_W64, + Tok_Varadic_Argument, + Tok___Attributes_Start, + Tok_Attribute_API_Export, + Tok_Attribute_API_Import, + Tok_NumTokens +}; + +inline StrC toktype_to_str( TokType type ) +{ + local_persist StrC lookup[] = { + { sizeof( "__invalid__" ), "__invalid__" }, + { sizeof( "private" ), "private" }, + { sizeof( "protected" ), "protected" }, + { sizeof( "public" ), "public" }, + { sizeof( "." ), "." }, + { sizeof( "::" ), "::" }, + { sizeof( "&" ), "&" }, + { sizeof( "&&" ), "&&" }, + { sizeof( ":" ), ":" }, + { sizeof( "[[" ), "[[" }, + { sizeof( "]]" ), "]]" }, + { sizeof( "{" ), "{" }, + { sizeof( "}" ), "}" }, + { sizeof( "[" ), "[" }, + { sizeof( "]" ), "]" }, + { sizeof( "(" ), "(" }, + { sizeof( ")" ), ")" }, + { sizeof( "__comment__" ), "__comment__" }, + { sizeof( "__comment_end__" ), "__comment_end__" }, + { sizeof( "__comment_start__" ), "__comment_start__" }, + { sizeof( "__character__" ), "__character__" }, + { sizeof( "," ), "," }, + { sizeof( "class" ), "class" }, + { sizeof( "__attribute__" ), "__attribute__" }, + { sizeof( "__declspec" ), "__declspec" }, + { sizeof( "enum" ), "enum" }, + { sizeof( "extern" ), "extern" }, + { sizeof( "friend" ), "friend" }, + { sizeof( "module" ), "module" }, + { sizeof( "namespace" ), "namespace" }, + { sizeof( "operator" ), "operator" }, + { sizeof( "struct" ), "struct" }, + { sizeof( "template" ), "template" }, + { sizeof( "typedef" ), "typedef" }, + { sizeof( "using" ), "using" }, + { sizeof( "union" ), "union" }, + { sizeof( "__identifier__" ), "__identifier__" }, + { sizeof( "import" ), "import" }, + { sizeof( "export" ), "export" }, + { sizeof( "__new_line__" ), "__new_line__" }, + { sizeof( "__number__" ), "__number__" }, + { sizeof( "__operator__" ), "__operator__" }, + { sizeof( "#" ), "#" }, + { sizeof( "define" ), "define" }, + { sizeof( "if" ), "if" }, + { sizeof( "ifdef" ), "ifdef" }, + { sizeof( "ifndef" ), "ifndef" }, + { sizeof( "elif" ), "elif" }, + { sizeof( "else" ), "else" }, + { sizeof( "endif" ), "endif" }, + { sizeof( "include" ), "include" }, + { sizeof( "pragma" ), "pragma" }, + { sizeof( "__macro_content__" ), "__macro_content__" }, + { sizeof( "__macro__" ), "__macro__" }, + { sizeof( "__unsupported__" ), "__unsupported__" }, + { sizeof( "alignas" ), "alignas" }, + { sizeof( "const" ), "const" }, + { sizeof( "consteval" ), "consteval" }, + { sizeof( "constexpr" ), "constexpr" }, + { sizeof( "constinit" ), "constinit" }, + { sizeof( "explicit" ), "explicit" }, + { sizeof( "extern" ), "extern" }, + { sizeof( "final" ), "final" }, + { sizeof( "forceinline" ), "forceinline" }, + { sizeof( "global" ), "global" }, + { sizeof( "inline" ), "inline" }, + { sizeof( "internal" ), "internal" }, + { sizeof( "local_persist" ), "local_persist" }, + { sizeof( "mutable" ), "mutable" }, + { sizeof( "neverinline" ), "neverinline" }, + { sizeof( "override" ), "override" }, + { sizeof( "static" ), "static" }, + { sizeof( "thread_local" ), "thread_local" }, + { sizeof( "volatile" ), "volatile" }, + { sizeof( "virtual" ), "virtual" }, + { sizeof( "*" ), "*" }, + { sizeof( ";" ), ";" }, + { sizeof( "static_assert" ), "static_assert" }, + { sizeof( "__string__" ), "__string__" }, + { sizeof( "typename" ), "typename" }, + { sizeof( "unsigned" ), "unsigned" }, + { sizeof( "signed" ), "signed" }, + { sizeof( "short" ), "short" }, + { sizeof( "long" ), "long" }, + { sizeof( "bool" ), "bool" }, + { sizeof( "char" ), "char" }, + { sizeof( "int" ), "int" }, + { sizeof( "double" ), "double" }, + { sizeof( "__int8" ), "__int8" }, + { sizeof( "__int16" ), "__int16" }, + { sizeof( "__int32" ), "__int32" }, + { sizeof( "__int64" ), "__int64" }, + { sizeof( "_W64" ), "_W64" }, + { sizeof( "..." ), "..." }, + { sizeof( "__attrib_start__" ), "__attrib_start__" }, + { sizeof( "GEN_API_Export_Code" ), "GEN_API_Export_Code" }, + { sizeof( "GEN_API_Import_Code" ), "GEN_API_Import_Code" }, + }; + return lookup[type]; +} + +inline TokType strc_to_toktype( StrC str ) +{ + local_persist u32 keymap[Tok_NumTokens]; + do_once_start for ( u32 index = 0; index < Tok_NumTokens; index++ ) + { + StrC enum_str = toktype_to_str( (TokType)index ); + keymap[index] = crc32( enum_str.Ptr, enum_str.Len - 1 ); + } + do_once_end u32 hash = crc32( str.Ptr, str.Len ); + for ( u32 index = 0; index < Tok_NumTokens; index++ ) + { + if ( keymap[index] == hash ) + return (TokType)index; + } + return Tok_Invalid; +} + +GEN_NS_PARSER_END diff --git a/project/components/header_end.hpp b/base/components/header_end.hpp similarity index 65% rename from project/components/header_end.hpp rename to base/components/header_end.hpp index 39cc1f2..2cbc306 100644 --- a/project/components/header_end.hpp +++ b/base/components/header_end.hpp @@ -24,8 +24,8 @@ #ifndef GEN_MAX_UNTYPED_STR_LENGTH # define GEN_MAX_UNTYPED_STR_LENGTH megabytes(1) #endif -#ifndef GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE -# define GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE kilobytes(4) +#ifndef TokenMap_FixedArena +# define TokenMap_FixedArena FixedArena_8KB #endif #ifndef GEN_LEX_ALLOCATOR_SIZE # define GEN_LEX_ALLOCATOR_SIZE megabytes(4) @@ -42,17 +42,19 @@ constexpr s32 InitSize_DataArrays = 16; // NOTE: This limits the maximum size of an allocation // If you are generating a string larger than this, increase the size of the bucket here. -constexpr usize Global_BucketSize = GEN_GLOBAL_BUCKET_SIZE; +constexpr usize Global_BucketSize = GEN_GLOBAL_BUCKET_SIZE; constexpr s32 CodePool_NumBlocks = GEN_CODEPOOL_NUM_BLOCKS; constexpr s32 SizePer_StringArena = GEN_SIZE_PER_STRING_ARENA; constexpr s32 MaxCommentLineLength = GEN_MAX_COMMENT_LINE_LENGTH; constexpr s32 MaxNameLength = GEN_MAX_NAME_LENGTH; constexpr s32 MaxUntypedStrLength = GEN_MAX_UNTYPED_STR_LENGTH; -constexpr s32 TokenFmt_TokenMap_MemSize = GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE; +// constexpr s32 TokenFmt_TokenMap_MemSize = GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE; constexpr s32 LexAllocator_Size = GEN_LEX_ALLOCATOR_SIZE; constexpr s32 Builder_StrBufferReserve = GEN_BUILDER_STR_BUFFER_RESERVE; +extern StrC enum_underlying_sig; + extern Code access_public; extern Code access_protected; extern Code access_private; @@ -67,7 +69,7 @@ extern Code fmt_newline; extern CodePragma pragma_once; -extern CodeParam param_varadic; +extern CodeParams param_varadic; extern CodePreprocessCond preprocess_else; extern CodePreprocessCond preprocess_endif; @@ -97,76 +99,52 @@ extern CodeSpecifiers spec_thread_local; extern CodeSpecifiers spec_virtual; extern CodeSpecifiers spec_volatile; -extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) -extern CodeType t_auto; -extern CodeType t_void; -extern CodeType t_int; -extern CodeType t_bool; -extern CodeType t_char; -extern CodeType t_wchar_t; -extern CodeType t_class; -extern CodeType t_typename; +extern CodeTypename t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance) +extern CodeTypename t_auto; +extern CodeTypename t_void; +extern CodeTypename t_int; +extern CodeTypename t_bool; +extern CodeTypename t_char; +extern CodeTypename t_wchar_t; +extern CodeTypename t_class; +extern CodeTypename t_typename; #ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS // Predefined typename codes. Are set to readonly and are setup during gen::init() - extern CodeType t_b32; + extern CodeTypename t_b32; - extern CodeType t_s8; - extern CodeType t_s16; - extern CodeType t_s32; - extern CodeType t_s64; + extern CodeTypename t_s8; + extern CodeTypename t_s16; + extern CodeTypename t_s32; + extern CodeTypename t_s64; - extern CodeType t_u8; - extern CodeType t_u16; - extern CodeType t_u32; - extern CodeType t_u64; + extern CodeTypename t_u8; + extern CodeTypename t_u16; + extern CodeTypename t_u32; + extern CodeTypename t_u64; - extern CodeType t_ssize; - extern CodeType t_usize; + extern CodeTypename t_ssize; + extern CodeTypename t_usize; - extern CodeType t_f32; - extern CodeType t_f64; + extern CodeTypename t_f32; + extern CodeTypename t_f64; #endif #pragma endregion Constants -#pragma region Macros - -# define gen_main main - -# define __ NoCode - - // Convienence for defining any name used with the gen api. - // Lets you provide the length and string literal to the functions without the need for the DSL. -# define name( Id_ ) { sizeof(stringize( Id_ )) - 1, stringize(Id_) } - - // Same as name just used to indicate intention of literal for code instead of names. -# define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) } - -# define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ - -# define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) -# define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) - - // Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. -# define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) - -#pragma endregion Macros - // Used by the lexer to persistently treat all these identifiers as preprocessor defines. // Populate with strings via gen::get_cached_string. // Functional defines must have format: id( ;at minimum to indicate that the define is only valid with arguments. -extern Array< StringCached > PreprocessorDefines; +extern Array(StringCached) PreprocessorDefines; #ifdef GEN_EXPOSE_BACKEND - // Global allocator used for data with process lifetime. extern AllocatorInfo GlobalAllocator; - extern Array< Arena > Global_AllocatorBuckets; + extern Array(Arena) Global_AllocatorBuckets; - extern Array< Pool > CodePools; - extern Array< Arena > StringArenas; + extern Array(Pool) CodePools; + extern Array(Arena) StringArenas; extern StringTable StringCache; @@ -178,5 +156,4 @@ extern Array< StringCached > PreprocessorDefines; extern AllocatorInfo Allocator_StringArena; extern AllocatorInfo Allocator_StringTable; extern AllocatorInfo Allocator_TypeTable; - #endif diff --git a/base/components/header_start.hpp b/base/components/header_start.hpp new file mode 100644 index 0000000..f356e72 --- /dev/null +++ b/base/components/header_start.hpp @@ -0,0 +1,32 @@ +#pragma once + +/* + gencpp: An attempt at "simple" staged metaprogramming for c/c++. + + See Readme.md for more information from the project repository. + + Public Address: + https://github.com/Ed94/gencpp --------------------------------------------------------------. + | _____ _____ _ _ | + | / ____) / ____} | | | | + | | / ___ ___ _ __ ___ _ __ _ __ | {___ | |__ _ _, __ _, ___ __| | | + | | |{_ |/ _ \ '_ \ / __} '_ l| '_ l `\___ \| __/ _` |/ _` |/ _ \/ _` | | + | | l__j | ___/ | | | {__; |+l } |+l | ____) | l| (_| | {_| | ___/ (_| | | + | \_____|\___}_l |_|\___} ,__/| ,__/ (_____/ \__\__/_|\__, |\___}\__,_l | + | | | | | __} | | + | l_l l_l {___/ | + ! ----------------------------------------------------------------------- VERSION: v0.20-Alpha | + ! ============================================================================================ | + ! WARNING: THIS IS AN ALPHA VERSION OF THE LIBRARY, USE AT YOUR OWN DISCRETION | + ! NEVER DO CODE GENERATION WITHOUT AT LEAST HAVING CONTENT IN A CODEBASE UNDER VERSION CONTROL | + ! ============================================================================================ / +*/ +#if ! defined(GEN_DONT_ENFORCE_GEN_TIME_GUARD) && ! defined(GEN_TIME) +# error Gen.hpp : GEN_TIME not defined +#endif + +//! If its desired to roll your own dependencies, define GEN_ROLL_OWN_DEPENDENCIES before including this file. +// Dependencies are derived from the c-zpl library: https://github.com/zpl-c/zpl +#ifndef GEN_ROLL_OWN_DEPENDENCIES +# include "gen.dep.hpp" +#endif diff --git a/base/components/inlines.hpp b/base/components/inlines.hpp new file mode 100644 index 0000000..70bc45d --- /dev/null +++ b/base/components/inlines.hpp @@ -0,0 +1,414 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "interface.hpp" +#endif + +#pragma region Code +inline +void code_append( Code self, Code other ) +{ + GEN_ASSERT(self); + GEN_ASSERT(other); + GEN_ASSERT_MSG(self != other, "Attempted to recursively append Code AST to itself."); + + if ( other->Parent != nullptr ) + other = code_duplicate(other); + + other->Parent = self; + + if ( self->Front == nullptr ) + { + self->Front = other; + self->Back = other; + + self->NumEntries++; + return; + } + + Code + Current = self->Back; + Current->Next = other; + other->Prev = Current; + self->Back = other; + self->NumEntries++; +} +inline +bool code_is_body(Code self) +{ + GEN_ASSERT(self); + switch (self->Type) + { + case CT_Enum_Body: + case CT_Class_Body: + case CT_Union_Body: + case CT_Export_Body: + case CT_Global_Body: + case CT_Struct_Body: + case CT_Function_Body: + case CT_Namespace_Body: + case CT_Extern_Linkage_Body: + return true; + } + return false; +} +inline +Code* code_entry( Code self, u32 idx ) +{ + GEN_ASSERT(self != nullptr); + Code* current = & self->Front; + while ( idx >= 0 && current != nullptr ) + { + if ( idx == 0 ) + return rcast( Code*, current); + + current = & ( * current )->Next; + idx--; + } + + return rcast( Code*, current); +} +forceinline +bool code_is_valid(Code self) +{ + GEN_ASSERT(self); + return self != nullptr && self->Type != CT_Invalid; +} +forceinline +bool code_has_entries(AST* self) +{ + GEN_ASSERT(self); + return self->NumEntries > 0; +} +forceinline +void code_set_global(Code self) +{ + if ( self == nullptr ) + { + log_failure("Code::set_global: Cannot set code as global, AST is null!"); + return; + } + + self->Parent = Code_Global; +} +#if GEN_COMPILER_CPP +forceinline +Code& Code::operator ++() +{ + if ( ast ) + ast = ast->Next.ast; + + return * this; +} +#endif +forceinline +StrC code_type_str(Code self) +{ + GEN_ASSERT(self != nullptr); + return codetype_to_str( self->Type ); +} +#pragma endregion Code + +#pragma region CodeBody +inline +void body_append( CodeBody self, Code other ) +{ + GEN_ASSERT(self); + GEN_ASSERT(other); + + if (code_is_body(other)) { + body_append_body( self, cast(CodeBody, other) ); + return; + } + + code_append( cast(Code, self), other ); +} +inline +void body_append_body( CodeBody self, CodeBody body ) +{ + GEN_ASSERT(self); + GEN_ASSERT(body); + GEN_ASSERT_MSG(self != body, "Attempted to append body to itself."); + + for ( Code entry = begin_CodeBody(body); entry != end_CodeBody(body); entry = next_CodeBody(body, entry) ) { + body_append( self, entry ); + } +} +inline +Code begin_CodeBody( CodeBody body) { + GEN_ASSERT(body); + if ( body != nullptr ) + return body->Front; + + return NullCode; +} +forceinline +Code end_CodeBody(CodeBody body ){ + GEN_ASSERT(body); + return body->Back->Next; +} +inline +Code next_CodeBody(CodeBody body, Code entry) { + GEN_ASSERT(body); + GEN_ASSERT(entry); + return entry->Next; +} +#pragma endregion CodeBody + +#pragma region CodeClass +inline +void class_add_interface( CodeClass self, CodeTypename type ) +{ + GEN_ASSERT(self); + GEN_ASSERT(type); + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) + { + // Were adding an interface to parent type, so we need to make sure the parent type is public. + self->ParentAccess = AccessSpec_Public; + // If your planning on adding a proper parent, + // then you'll need to move this over to ParentType->next and update ParentAccess accordingly. + } + + while ( possible_slot != nullptr ) + { + possible_slot = cast(CodeTypename, possible_slot->Next); + } + + possible_slot = type; +} +#pragma endregion CodeClass + +#pragma region CodeParams +inline +void params_append( CodeParams appendee, CodeParams other ) +{ + GEN_ASSERT(appendee); + GEN_ASSERT(other); + GEN_ASSERT_MSG(appendee != other, "Attempted to append parameter to itself."); + Code self = cast(Code, appendee); + Code entry = cast(Code, other); + + if ( entry->Parent != nullptr ) + entry = code_duplicate( entry ); + + entry->Parent = self; + + if ( self->Last == nullptr ) + { + self->Last = entry; + self->Next = entry; + self->NumEntries++; + return; + } + + self->Last->Next = entry; + self->Last = entry; + self->NumEntries++; +} +inline +CodeParams params_get(CodeParams self, s32 idx ) +{ + GEN_ASSERT(self); + CodeParams param = self; + do + { + if ( ++ param != nullptr ) + return NullCode; + + param = cast(CodeParams, cast(Code, param)->Next); + } + while ( --idx ); + + return param; +} +forceinline +bool params_has_entries(CodeParams self) +{ + GEN_ASSERT(self); + return self->NumEntries > 0; +} +#if GEN_COMPILER_CPP +forceinline +CodeParams& CodeParams::operator ++() +{ + * this = ast->Next; + return * this; +} +#endif +forceinline +CodeParams begin_CodeParams(CodeParams params) +{ + if ( params != nullptr ) + return params; + + return NullCode; +} +forceinline +CodeParams end_CodeParams(CodeParams params) +{ + // return { (AST_Params*) rcast( AST*, ast)->Last }; + return NullCode; +} +forceinline +CodeParams next_CodeParams(CodeParams params, CodeParams param_iter) +{ + GEN_ASSERT(param_iter); + return param_iter->Next; +} +#pragma endregion CodeParams + +#pragma region CodeSpecifiers +inline +bool specifiers_append(CodeSpecifiers self, Specifier spec ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return false; + } + if ( self->NumEntries == AST_ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); + return false; + } + + self->ArrSpecs[ self->NumEntries ] = spec; + self->NumEntries++; + return true; +} +inline +s32 specifiers_has(CodeSpecifiers self, Specifier spec) +{ + GEN_ASSERT(self != nullptr); + for ( s32 idx = 0; idx < self->NumEntries; idx++ ) { + if ( self->ArrSpecs[ idx ] == spec ) + return idx; + } + return -1; +} +inline +s32 specifiers_remove( CodeSpecifiers self, Specifier to_remove ) +{ + if ( self == nullptr ) + { + log_failure("CodeSpecifiers: Attempted to append to a null specifiers AST!"); + return -1; + } + if ( self->NumEntries == AST_ArrSpecs_Cap ) + { + log_failure("CodeSpecifiers: Attempted to append over %d specifiers to a specifiers AST!", AST_ArrSpecs_Cap ); + return -1; + } + + s32 result = -1; + + s32 curr = 0; + s32 next = 0; + for(; next < self->NumEntries; ++ curr, ++ next) + { + Specifier spec = self->ArrSpecs[next]; + if (spec == to_remove) + { + result = next; + + next ++; + if (next >= self->NumEntries) + break; + + spec = self->ArrSpecs[next]; + } + + self->ArrSpecs[ curr ] = spec; + } + + if (result > -1) { + self->NumEntries --; + } + return result; +} +forceinline +Specifier* begin_CodeSpecifiers(CodeSpecifiers self) +{ + if ( self != nullptr ) + return & self->ArrSpecs[0]; + + return nullptr; +} +forceinline +Specifier* end_CodeSpecifiers(CodeSpecifiers self) +{ + return self->ArrSpecs + self->NumEntries; +} +forceinline +Specifier* next_CodeSpecifiers(CodeSpecifiers self, Specifier* spec_iter) +{ + return spec_iter + 1; +} +#pragma endregion CodeSpecifiers + +#pragma region CodeStruct +inline +void struct_add_interface(CodeStruct self, CodeTypename type ) +{ + CodeTypename possible_slot = self->ParentType; + if ( possible_slot != nullptr ) + { + // Were adding an interface to parent type, so we need to make sure the parent type is public. + self->ParentAccess = AccessSpec_Public; + // If your planning on adding a proper parent, + // then you'll need to move this over to ParentType->next and update ParentAccess accordingly. + } + + while ( possible_slot != nullptr ) + { + possible_slot = cast(CodeTypename, possible_slot->Next); + } + + possible_slot = type; +} +#pragma endregion Code + +#pragma region Interface +inline +CodeBody def_body( CodeType type ) +{ + switch ( type ) + { + case CT_Class_Body: + case CT_Enum_Body: + case CT_Export_Body: + case CT_Extern_Linkage: + case CT_Function_Body: + case CT_Global_Body: + case CT_Namespace_Body: + case CT_Struct_Body: + case CT_Union_Body: + break; + + default: + log_failure( "def_body: Invalid type %s", codetype_to_str(type).Ptr ); + return (CodeBody)Code_Invalid; + } + + Code + result = make_code(); + result->Type = type; + return (CodeBody)result; +} + +inline +StrC token_fmt_impl( ssize num, ... ) +{ + local_persist thread_local + char buf[GEN_PRINTF_MAXLEN] = { 0 }; + mem_set( buf, 0, GEN_PRINTF_MAXLEN ); + + va_list va; + va_start(va, num ); + ssize result = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num, va); + va_end(va); + + StrC str = { result, buf }; + return str; +} +#pragma endregion Interface diff --git a/base/components/interface.cpp b/base/components/interface.cpp new file mode 100644 index 0000000..b713dde --- /dev/null +++ b/base/components/interface.cpp @@ -0,0 +1,462 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "code_serialization.cpp" +#endif + +GEN_NS_PARSER_BEGIN +internal void parser_init(); +internal void parser_deinit(); +GEN_NS_PARSER_END + +internal +void* Global_Allocator_Proc( void* allocator_data, AllocType type, ssize size, ssize alignment, void* old_memory, ssize old_size, u64 flags ) +{ + Arena* last = array_back(Global_AllocatorBuckets); + + switch ( type ) + { + case EAllocation_ALLOC: + { + if ( ( last->TotalUsed + size ) > last->TotalSize ) + { + Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); + + if ( bucket.PhysicalStart == nullptr ) + GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); + + if ( ! array_append( Global_AllocatorBuckets, bucket ) ) + GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); + + last = array_back(Global_AllocatorBuckets); + } + + return alloc_align( arena_allocator_info(last), size, alignment ); + } + case EAllocation_FREE: + { + // Doesn't recycle. + } + break; + case EAllocation_FREE_ALL: + { + // Memory::cleanup instead. + } + break; + case EAllocation_RESIZE: + { + if ( last->TotalUsed + size > last->TotalSize ) + { + Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); + + if ( bucket.PhysicalStart == nullptr ) + GEN_FATAL( "Failed to create bucket for Global_AllocatorBuckets"); + + if ( ! array_append( Global_AllocatorBuckets, bucket ) ) + GEN_FATAL( "Failed to append bucket to Global_AllocatorBuckets"); + + last = array_back(Global_AllocatorBuckets); + } + + void* result = alloc_align( last->Backing, size, alignment ); + + if ( result != nullptr && old_memory != nullptr ) + { + mem_copy( result, old_memory, old_size ); + } + + return result; + } + } + + return nullptr; +} + +internal +void define_constants() +{ + Code_Global = make_code(); + Code_Global->Name = get_cached_string( txt("Global Code") ); + Code_Global->Content = Code_Global->Name; + + Code_Invalid = make_code(); + code_set_global(Code_Invalid); + + t_empty = (CodeTypename) make_code(); + t_empty->Type = CT_Typename; + t_empty->Name = get_cached_string( txt("") ); + code_set_global(cast(Code, t_empty)); + + access_private = make_code(); + access_private->Type = CT_Access_Private; + access_private->Name = get_cached_string( txt("private:\n") ); + code_set_global(cast(Code, access_private)); + + access_protected = make_code(); + access_protected->Type = CT_Access_Protected; + access_protected->Name = get_cached_string( txt("protected:\n") ); + code_set_global(access_protected); + + access_public = make_code(); + access_public->Type = CT_Access_Public; + access_public->Name = get_cached_string( txt("public:\n") ); + code_set_global(access_public); + + StrC api_export_str = code(GEN_API_Export_Code); + attrib_api_export = def_attributes( api_export_str ); + code_set_global(cast(Code, attrib_api_export)); + + StrC api_import_str = code(GEN_API_Import_Code); + attrib_api_import = def_attributes( api_import_str ); + code_set_global(cast(Code, attrib_api_import)); + + module_global_fragment = make_code(); + module_global_fragment->Type = CT_Untyped; + module_global_fragment->Name = get_cached_string( txt("module;") ); + module_global_fragment->Content = module_global_fragment->Name; + code_set_global(cast(Code, module_global_fragment)); + + module_private_fragment = make_code(); + module_private_fragment->Type = CT_Untyped; + module_private_fragment->Name = get_cached_string( txt("module : private;") ); + module_private_fragment->Content = module_private_fragment->Name; + code_set_global(cast(Code, module_private_fragment)); + + fmt_newline = make_code(); + fmt_newline->Type = CT_NewLine; + code_set_global((Code)fmt_newline); + + pragma_once = (CodePragma) make_code(); + pragma_once->Type = CT_Preprocess_Pragma; + pragma_once->Name = get_cached_string( txt("once") ); + pragma_once->Content = pragma_once->Name; + code_set_global((Code)pragma_once); + + param_varadic = (CodeParams) make_code(); + param_varadic->Type = CT_Parameters; + param_varadic->Name = get_cached_string( txt("...") ); + param_varadic->ValueType = t_empty; + code_set_global((Code)param_varadic); + + preprocess_else = (CodePreprocessCond) make_code(); + preprocess_else->Type = CT_Preprocess_Else; + code_set_global((Code)preprocess_else); + + preprocess_endif = (CodePreprocessCond) make_code(); + preprocess_endif->Type = CT_Preprocess_EndIf; + code_set_global((Code)preprocess_endif); + +# define def_constant_code_type( Type_ ) \ + do \ + { \ + StrC name_str = name(Type_); \ + t_##Type_ = def_type( name_str ); \ + code_set_global( cast(Code, t_##Type_)); \ + } while(0) + + def_constant_code_type( auto ); + def_constant_code_type( void ); + def_constant_code_type( int ); + def_constant_code_type( bool ); + def_constant_code_type( char ); + def_constant_code_type( wchar_t ); + def_constant_code_type( class ); + def_constant_code_type( typename ); + +#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS + t_b32 = def_type( name(b32) ); + + def_constant_code_type( s8 ); + def_constant_code_type( s16 ); + def_constant_code_type( s32 ); + def_constant_code_type( s64 ); + + def_constant_code_type( u8 ); + def_constant_code_type( u16 ); + def_constant_code_type( u32 ); + def_constant_code_type( u64 ); + + def_constant_code_type( ssize ); + def_constant_code_type( usize ); + + def_constant_code_type( f32 ); + def_constant_code_type( f64 ); +#endif +# undef def_constant_code_type + + spec_const = def_specifier( Spec_Const); code_set_global( cast(Code, spec_const )); + spec_consteval = def_specifier( Spec_Consteval); code_set_global( cast(Code, spec_consteval ));; + spec_constexpr = def_specifier( Spec_Constexpr); code_set_global( cast(Code, spec_constexpr ));; + spec_constinit = def_specifier( Spec_Constinit); code_set_global( cast(Code, spec_constinit ));; + spec_extern_linkage = def_specifier( Spec_External_Linkage); code_set_global( cast(Code, spec_extern_linkage ));; + spec_final = def_specifier( Spec_Final); code_set_global( cast(Code, spec_final ));; + spec_forceinline = def_specifier( Spec_ForceInline); code_set_global( cast(Code, spec_forceinline ));; + spec_global = def_specifier( Spec_Global); code_set_global( cast(Code, spec_global ));; + spec_inline = def_specifier( Spec_Inline); code_set_global( cast(Code, spec_inline ));; + spec_internal_linkage = def_specifier( Spec_Internal_Linkage); code_set_global( cast(Code, spec_internal_linkage ));; + spec_local_persist = def_specifier( Spec_Local_Persist); code_set_global( cast(Code, spec_local_persist ));; + spec_mutable = def_specifier( Spec_Mutable); code_set_global( cast(Code, spec_mutable ));; + spec_neverinline = def_specifier( Spec_NeverInline); code_set_global( cast(Code, spec_neverinline ));; + spec_noexcept = def_specifier( Spec_NoExceptions); code_set_global( cast(Code, spec_noexcept ));; + spec_override = def_specifier( Spec_Override); code_set_global( cast(Code, spec_override ));; + spec_ptr = def_specifier( Spec_Ptr); code_set_global( cast(Code, spec_ptr ));; + spec_pure = def_specifier( Spec_Pure); code_set_global( cast(Code, spec_pure )); + spec_ref = def_specifier( Spec_Ref); code_set_global( cast(Code, spec_ref ));; + spec_register = def_specifier( Spec_Register); code_set_global( cast(Code, spec_register ));; + spec_rvalue = def_specifier( Spec_RValue); code_set_global( cast(Code, spec_rvalue ));; + spec_static_member = def_specifier( Spec_Static); code_set_global( cast(Code, spec_static_member ));; + spec_thread_local = def_specifier( Spec_Thread_Local); code_set_global( cast(Code, spec_thread_local ));; + spec_virtual = def_specifier( Spec_Virtual); code_set_global( cast(Code, spec_virtual ));; + spec_volatile = def_specifier( Spec_Volatile); code_set_global( cast(Code, spec_volatile )); + + spec_local_persist = def_specifiers( 1, Spec_Local_Persist ); + code_set_global(cast(Code, spec_local_persist)); + + if (enum_underlying_sig.Len == 0) { + enum_underlying_sig = txt("enum_underlying("); + } + array_append(PreprocessorDefines, enum_underlying_sig); + +# undef def_constant_spec +} + +void init() +{ + // Setup global allocator + { + AllocatorInfo becasue_C = { & Global_Allocator_Proc, nullptr }; + GlobalAllocator = becasue_C; + + Global_AllocatorBuckets = array_init_reserve(Arena, heap(), 128 ); + + if ( Global_AllocatorBuckets == nullptr ) + GEN_FATAL( "Failed to reserve memory for Global_AllocatorBuckets"); + + Arena bucket = arena_init_from_allocator( heap(), Global_BucketSize ); + + if ( bucket.PhysicalStart == nullptr ) + GEN_FATAL( "Failed to create first bucket for Global_AllocatorBuckets"); + + array_append( Global_AllocatorBuckets, bucket ); + } + + if (Allocator_DataArrays.Proc == nullptr) { + Allocator_DataArrays = GlobalAllocator; + } + if (Allocator_CodePool.Proc == nullptr ) { + Allocator_CodePool = GlobalAllocator; + } + if (Allocator_Lexer.Proc == nullptr) { + Allocator_Lexer = GlobalAllocator; + } + if (Allocator_StringArena.Proc == nullptr) { + Allocator_StringArena = GlobalAllocator; + } + if (Allocator_StringTable.Proc == nullptr) { + Allocator_StringTable = GlobalAllocator; + } + if (Allocator_TypeTable.Proc == nullptr) { + Allocator_TypeTable = GlobalAllocator; + } + + // Setup the arrays + { + CodePools = array_init_reserve(Pool, Allocator_DataArrays, InitSize_DataArrays ); + + if ( CodePools == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the CodePools array" ); + + StringArenas = array_init_reserve(Arena, Allocator_DataArrays, InitSize_DataArrays ); + + if ( StringArenas == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the StringArenas array" ); + } + + // Setup the code pool and code entries arena. + { + Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); + + if ( code_pool.PhysicalStart == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the code pool" ); + + array_append( CodePools, code_pool ); + + LexArena = arena_init_from_allocator( Allocator_Lexer, LexAllocator_Size ); + + Arena string_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); + + if ( string_arena.PhysicalStart == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the string arena" ); + + array_append( StringArenas, string_arena ); + } + + // Setup the hash tables + { + StringCache = hashtable_init(StringCached, Allocator_StringTable); + + if ( StringCache.Entries == nullptr ) + GEN_FATAL( "gen::init: Failed to initialize the StringCache"); + } + + // Preprocessor Defines + PreprocessorDefines = array_init_reserve(StringCached, GlobalAllocator, kilobytes(1) ); + + define_constants(); + GEN_NS_PARSER parser_init(); +} + +void deinit() +{ + usize index = 0; + usize left = array_num(CodePools); + do + { + Pool* code_pool = & CodePools[index]; + pool_free(code_pool); + index++; + } + while ( left--, left ); + + index = 0; + left = array_num(StringArenas); + do + { + Arena* string_arena = & StringArenas[index]; + arena_free(string_arena); + index++; + } + while ( left--, left ); + + hashtable_destroy(StringCache); + + array_free( CodePools); + array_free( StringArenas); + + arena_free(& LexArena); + + array_free(PreprocessorDefines); + + index = 0; + left = array_num(Global_AllocatorBuckets); + do + { + Arena* bucket = & Global_AllocatorBuckets[ index ]; + arena_free(bucket); + index++; + } + while ( left--, left ); + + array_free(Global_AllocatorBuckets); + GEN_NS_PARSER parser_deinit(); +} + +void reset() +{ + s32 index = 0; + s32 left = array_num(CodePools); + do + { + Pool* code_pool = & CodePools[index]; + pool_clear(code_pool); + index++; + } + while ( left--, left ); + + index = 0; + left = array_num(StringArenas); + do + { + Arena* string_arena = & StringArenas[index]; + string_arena->TotalUsed = 0;; + index++; + } + while ( left--, left ); + + hashtable_clear(StringCache); + + define_constants(); +} + +AllocatorInfo get_string_allocator( s32 str_length ) +{ + Arena* last = array_back(StringArenas); + + usize size_req = str_length + sizeof(StringHeader) + sizeof(char*); + + if ( last->TotalUsed + scast(ssize, size_req) > last->TotalSize ) + { + Arena new_arena = arena_init_from_allocator( Allocator_StringArena, SizePer_StringArena ); + + if ( ! array_append( StringArenas, new_arena ) ) + GEN_FATAL( "gen::get_string_allocator: Failed to allocate a new string arena" ); + + last = array_back(StringArenas); + } + + return arena_allocator_info(last); +} + +// Will either make or retrive a code string. +StringCached get_cached_string( StrC str ) +{ + s32 hash_length = str.Len > kilobytes(1) ? kilobytes(1) : str.Len; + u64 key = crc32( str.Ptr, hash_length ); + { + StringCached* result = hashtable_get(StringCache, key ); + + if ( result ) + return * result; + } + + StrC result = string_to_strc( string_make_strc( get_string_allocator( str.Len ), str )); + hashtable_set(StringCache, key, result ); + + return result; +} + +// Used internally to retireve a Code object form the CodePool. +Code make_code() +{ + Pool* allocator = array_back( CodePools); + if ( allocator->FreeList == nullptr ) + { + Pool code_pool = pool_init( Allocator_CodePool, CodePool_NumBlocks, sizeof(AST) ); + + if ( code_pool.PhysicalStart == nullptr ) + GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePool allcoator returned nullptr." ); + + if ( ! array_append( CodePools, code_pool ) ) + GEN_FATAL( "gen::make_code: Failed to allocate a new code pool - CodePools failed to append new pool." ); + + allocator = array_back( CodePools); + } + + Code result = { rcast( AST*, alloc( pool_allocator_info(allocator), sizeof(AST) )) }; + mem_set( rcast(void*, cast(AST*, result)), 0, sizeof(AST) ); + return result; +} + +void set_allocator_data_arrays( AllocatorInfo allocator ) +{ + Allocator_DataArrays = allocator; +} + +void set_allocator_code_pool( AllocatorInfo allocator ) +{ + Allocator_CodePool = allocator; +} + +void set_allocator_lexer( AllocatorInfo allocator ) +{ + Allocator_Lexer = allocator; +} + +void set_allocator_string_arena( AllocatorInfo allocator ) +{ + Allocator_StringArena = allocator; +} + +void set_allocator_string_table( AllocatorInfo allocator ) +{ + Allocator_StringArena = allocator; +} diff --git a/base/components/interface.hpp b/base/components/interface.hpp new file mode 100644 index 0000000..2b08281 --- /dev/null +++ b/base/components/interface.hpp @@ -0,0 +1,347 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "ast_types.hpp" +#endif + +#pragma region Gen Interface +/* + / \ | \ | \ / \ +| ▓▓▓▓▓▓\ ______ _______ \▓▓▓▓▓▓_______ _| ▓▓_ ______ ______ | ▓▓▓▓▓▓\ ______ _______ ______ +| ▓▓ __\▓▓/ \| \ | ▓▓ | \| ▓▓ \ / \ / \| ▓▓_ \▓▓| \ / \/ \ +| ▓▓| \ ▓▓▓▓▓▓\ ▓▓▓▓▓▓▓\ | ▓▓ | ▓▓▓▓▓▓▓\\▓▓▓▓▓▓ | ▓▓▓▓▓▓\ ▓▓▓▓▓▓\ ▓▓ \ \▓▓▓▓▓▓\ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓\ +| ▓▓ \▓▓▓▓ ▓▓ ▓▓ ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ | ▓▓ __| ▓▓ ▓▓ ▓▓ \▓▓ ▓▓▓▓ / ▓▓ ▓▓ | ▓▓ ▓▓ +| ▓▓__| ▓▓ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ _| ▓▓_| ▓▓ | ▓▓ | ▓▓| \ ▓▓▓▓▓▓▓▓ ▓▓ | ▓▓ | ▓▓▓▓▓▓▓ ▓▓_____| ▓▓▓▓▓▓▓▓ + \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ | ▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \ ▓▓ | ▓▓ \▓▓ ▓▓\▓▓ \\▓▓ \ + \▓▓▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓ \▓▓▓▓▓▓▓\▓▓ \▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ \▓▓▓▓▓▓▓ +*/ + +// Initialize the library. +void init(); + +// Currently manually free's the arenas, code for checking for leaks. +// However on Windows at least, it doesn't need to occur as the OS will clean up after the process. +void deinit(); + +// Clears the allocations, but doesn't return to the heap, the calls init() again. +// Ease of use. +void reset(); + +// Used internally to retrive or make string allocations. +// Strings are stored in a series of string arenas of fixed size (SizePer_StringArena) +StringCached get_cached_string( StrC str ); + +/* + This provides a fresh Code AST. + The gen interface use this as their method from getting a new AST object from the CodePool. + Use this if you want to make your own API for formatting the supported Code Types. +*/ +Code make_code(); + +// Set these before calling gen's init() procedure. + +void set_allocator_data_arrays ( AllocatorInfo data_array_allocator ); +void set_allocator_code_pool ( AllocatorInfo pool_allocator ); +void set_allocator_lexer ( AllocatorInfo lex_allocator ); +void set_allocator_string_arena( AllocatorInfo string_allocator ); +void set_allocator_string_table( AllocatorInfo string_allocator ); +void set_allocator_type_table ( AllocatorInfo type_reg_allocator ); + +#pragma region Upfront + +CodeAttributes def_attributes( StrC content ); +CodeComment def_comment ( StrC content ); + +struct Opts_def_struct { + CodeBody body; + CodeTypename parent; + AccessSpec parent_access; + CodeAttributes attributes; + CodeTypename* interfaces; + s32 num_interfaces; + ModuleFlag mflags; +}; +CodeClass def_class( StrC name, Opts_def_struct opts GEN_PARAM_DEFAULT ); + +struct Opts_def_constructor { + CodeParams params; + Code initializer_list; + Code body; +}; +CodeConstructor def_constructor( Opts_def_constructor opts GEN_PARAM_DEFAULT ); + +struct Opts_def_define { + b32 dont_append_preprocess_defines; +}; +CodeDefine def_define( StrC name, StrC content, Opts_def_define opts GEN_PARAM_DEFAULT ); + +struct Opts_def_destructor { + Code body; + CodeSpecifiers specifiers; +}; +CodeDestructor def_destructor( Opts_def_destructor opts GEN_PARAM_DEFAULT ); + +struct Opts_def_enum { + CodeBody body; + CodeTypename type; + EnumT specifier; + CodeAttributes attributes; + ModuleFlag mflags; + Code type_macro; +}; +CodeEnum def_enum( StrC name, Opts_def_enum opts GEN_PARAM_DEFAULT ); + +CodeExec def_execution ( StrC content ); +CodeExtern def_extern_link( StrC name, CodeBody body ); +CodeFriend def_friend ( Code symbol ); + +struct Opts_def_function { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specs; + CodeAttributes attrs; + ModuleFlag mflags; +}; +CodeFn def_function( StrC name, Opts_def_function opts GEN_PARAM_DEFAULT ); + +struct Opts_def_include { b32 foreign; }; +struct Opts_def_module { ModuleFlag mflags; }; +struct Opts_def_namespace { ModuleFlag mflags; }; +CodeInclude def_include ( StrC content, Opts_def_include opts GEN_PARAM_DEFAULT ); +CodeModule def_module ( StrC name, Opts_def_module opts GEN_PARAM_DEFAULT ); +CodeNS def_namespace( StrC name, CodeBody body, Opts_def_namespace opts GEN_PARAM_DEFAULT ); + +struct Opts_def_operator { + CodeParams params; + CodeTypename ret_type; + CodeBody body; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +CodeOperator def_operator( Operator op, StrC nspace, Opts_def_operator opts GEN_PARAM_DEFAULT ); + +struct Opts_def_operator_cast { + CodeBody body; + CodeSpecifiers specs; +}; +CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast opts GEN_PARAM_DEFAULT ); + +struct Opts_def_param { Code value; }; +CodeParams def_param ( CodeTypename type, StrC name, Opts_def_param opts GEN_PARAM_DEFAULT ); +CodePragma def_pragma( StrC directive ); + +CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content ); + +CodeSpecifiers def_specifier( Specifier specifier ); + +CodeStruct def_struct( StrC name, Opts_def_struct opts GEN_PARAM_DEFAULT ); + +struct Opts_def_template { ModuleFlag mflags; }; +CodeTemplate def_template( CodeParams params, Code definition, Opts_def_template opts GEN_PARAM_DEFAULT ); + +struct Opts_def_type { + ETypenameTag type_tag; + Code arrayexpr; + CodeSpecifiers specifiers; + CodeAttributes attributes; +}; +CodeTypename def_type( StrC name, Opts_def_type opts GEN_PARAM_DEFAULT ); + +struct Opts_def_typedef { + CodeAttributes attributes; + ModuleFlag mflags; +}; +CodeTypedef def_typedef( StrC name, Code type, Opts_def_typedef opts GEN_PARAM_DEFAULT ); + +struct Opts_def_union { + CodeAttributes attributes; + ModuleFlag mflags; +}; +CodeUnion def_union( StrC name, CodeBody body, Opts_def_union opts GEN_PARAM_DEFAULT ); + +struct Opts_def_using { + CodeAttributes attributes; + ModuleFlag mflags; +}; +CodeUsing def_using( StrC name, CodeTypename type, Opts_def_using opts GEN_PARAM_DEFAULT ); + +CodeUsing def_using_namespace( StrC name ); + +struct Opts_def_variable +{ + Code value; + CodeSpecifiers specifiers; + CodeAttributes attributes; + ModuleFlag mflags; +}; +CodeVar def_variable( CodeTypename type, StrC name, Opts_def_variable opts GEN_PARAM_DEFAULT ); + +// Constructs an empty body. Use AST::validate_body() to check if the body is was has valid entries. +CodeBody def_body( CodeType type ); + +// There are two options for defining a struct body, either varadically provided with the args macro to auto-deduce the arg num, +/// or provide as an array of Code objects. + +CodeBody def_class_body ( s32 num, ... ); +CodeBody def_class_body ( s32 num, Code* codes ); +CodeBody def_enum_body ( s32 num, ... ); +CodeBody def_enum_body ( s32 num, Code* codes ); +CodeBody def_export_body ( s32 num, ... ); +CodeBody def_export_body ( s32 num, Code* codes); +CodeBody def_extern_link_body( s32 num, ... ); +CodeBody def_extern_link_body( s32 num, Code* codes ); +CodeBody def_function_body ( s32 num, ... ); +CodeBody def_function_body ( s32 num, Code* codes ); +CodeBody def_global_body ( s32 num, ... ); +CodeBody def_global_body ( s32 num, Code* codes ); +CodeBody def_namespace_body ( s32 num, ... ); +CodeBody def_namespace_body ( s32 num, Code* codes ); +CodeParams def_params ( s32 num, ... ); +CodeParams def_params ( s32 num, CodeParams* params ); +CodeSpecifiers def_specifiers ( s32 num, ... ); +CodeSpecifiers def_specifiers ( s32 num, Specifier* specs ); +CodeBody def_struct_body ( s32 num, ... ); +CodeBody def_struct_body ( s32 num, Code* codes ); +CodeBody def_union_body ( s32 num, ... ); +CodeBody def_union_body ( s32 num, Code* codes ); + +#pragma endregion Upfront + +#pragma region Parsing + +// TODO(Ed) : Implmeent the new parser API design. + +#if 0 +GEN_NS_PARSER_BEGIN +struct StackNode +{ + StackNode* Prev; + + Token Start; + Token Name; // The name of the AST node (if parsed) + StrC FailedProc; // The name of the procedure that failed +}; +// Stack nodes are allocated the error's allocator + +struct Error +{ + String message; + StackNode* context_stack; +}; +GEN_NS_PARSER_END + +struct ParseInfo +{ + Arena FileMem; + Arena TokMem; + Arena CodeMem; + + FileContents FileContent; + Array Tokens; + Array Errors; + // Errors are allocated to a dedicated general arena. +}; + +CodeBody parse_file( StrC path ); +#endif + +CodeClass parse_class ( StrC class_def ); +CodeConstructor parse_constructor ( StrC constructor_def ); +CodeDestructor parse_destructor ( StrC destructor_def ); +CodeEnum parse_enum ( StrC enum_def ); +CodeBody parse_export_body ( StrC export_def ); +CodeExtern parse_extern_link ( StrC exten_link_def ); +CodeFriend parse_friend ( StrC friend_def ); +CodeFn parse_function ( StrC fn_def ); +CodeBody parse_global_body ( StrC body_def ); +CodeNS parse_namespace ( StrC namespace_def ); +CodeOperator parse_operator ( StrC operator_def ); +CodeOpCast parse_operator_cast( StrC operator_def ); +CodeStruct parse_struct ( StrC struct_def ); +CodeTemplate parse_template ( StrC template_def ); +CodeTypename parse_type ( StrC type_def ); +CodeTypedef parse_typedef ( StrC typedef_def ); +CodeUnion parse_union ( StrC union_def ); +CodeUsing parse_using ( StrC using_def ); +CodeVar parse_variable ( StrC var_def ); + +#pragma endregion Parsing + +#pragma region Untyped text + +ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ); +//! Do not use directly. Use the token_fmt macro instead. +StrC token_fmt_impl( ssize, ... ); + +Code untyped_str ( StrC content); +Code untyped_fmt ( char const* fmt, ... ); +Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ); + +#pragma endregion Untyped text + +#pragma region Macros + +#ifndef gen_main +#define gen_main main +#endif + +#ifndef name +// Convienence for defining any name used with the gen api. +// Lets you provide the length and string literal to the functions without the need for the DSL. +#define name( Id_ ) { sizeof(stringize( Id_ )) - 1, stringize(Id_) } +#endif + +#ifndef code +// Same as name just used to indicate intention of literal for code instead of names. +#define code( ... ) { sizeof(stringize(__VA_ARGS__)) - 1, stringize( __VA_ARGS__ ) } +#endif + +#ifndef args +// Provides the number of arguments while passing args inplace. +#define args( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ +#endif + +#ifndef code_str +// Just wrappers over common untyped code definition constructions. +#define code_str( ... ) GEN_NS untyped_str( code( __VA_ARGS__ ) ) +#endif + +#ifndef code_fmt +#define code_fmt( ... ) GEN_NS untyped_str( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef parse_fmt +#define parse_fmt( type, ... ) GEN_NS parse_##type( token_fmt( __VA_ARGS__ ) ) +#endif + +#ifndef token_fmt +/* +Takes a format string (char const*) and a list of tokens (StrC) and returns a StrC of the formatted string. +Tokens are provided in '<'identifier'>' format where '<' '>' are just angle brackets (you can change it in token_fmt_va) +--------------------------------------------------------- + Example - A string with: + typedef ; + Will have a token_fmt arguments populated with: + "type", strc_for_type, + "name", strc_for_name, + and: + stringize( typedef ; ) +----------------------------------------------------------- +So the full call for this example would be: + token_fmt( + "type", strc_for_type + , "name", strc_for_name + , stringize( + typedef + )); +!---------------------------------------------------------- +! Note: token_fmt_va is whitespace sensitive for the tokens. +! This can be alleviated by skipping whitespace between brackets but it was choosen to not have that implementation by default. +*/ +#define token_fmt( ... ) GEN_NS token_fmt_impl( (num_args( __VA_ARGS__ ) + 1) / 2, __VA_ARGS__ ) +#endif + +#pragma endregion Macros + +#pragma endregion Gen Interface diff --git a/project/components/interface.parsing.cpp b/base/components/interface.parsing.cpp similarity index 56% rename from project/components/interface.parsing.cpp rename to base/components/interface.parsing.cpp index 726f9e4..d983e07 100644 --- a/project/components/interface.parsing.cpp +++ b/base/components/interface.parsing.cpp @@ -10,58 +10,58 @@ CodeClass parse_class( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; push_scope(); - CodeClass result = (CodeClass) parse_class_struct( TokType::Decl_Class ); - Context.pop(); + CodeClass result = (CodeClass) parse_class_struct( Tok_Decl_Class, parser_not_inplace_def ); + parser_pop(& Context); return result; } CodeConstructor parse_constructor( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; // TODO(Ed): Constructors can have prefix attributes - CodeSpecifiers specifiers; - SpecifierT specs_found[ 16 ] { ESpecifier::NumSpecifiers }; + CodeSpecifiers specifiers = NullCode; + Specifier specs_found[ 16 ] = { Spec_NumSpecifiers }; s32 NumSpecifiers = 0; - while ( left && currtok.is_specifier() ) + while ( left && tok_is_specifier(currtok) ) { - SpecifierT spec = ESpecifier::to_type( currtok ); + Specifier spec = strc_to_specifier( tok_to_str(currtok) ); b32 ignore_spec = false; switch ( spec ) { - case ESpecifier::Constexpr : - case ESpecifier::Explicit: - case ESpecifier::Inline : - case ESpecifier::ForceInline : - case ESpecifier::NeverInline : + case Spec_Constexpr : + case Spec_Explicit: + case Spec_Inline : + case Spec_ForceInline : + case Spec_NeverInline : break; - case ESpecifier::Const : + case Spec_Const : ignore_spec = true; break; default : - log_failure( "Invalid specifier %s for variable\n%s", ESpecifier::to_str( spec ), Context.to_string() ); - Context.pop(); - return CodeInvalid; + log_failure( "Invalid specifier %s for variable\n%s", spec_to_str( spec ), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; } // Every specifier after would be considered part of the type type signature @@ -80,250 +80,266 @@ CodeConstructor parse_constructor( StrC def ) } Context.Tokens = toks; - CodeConstructor result = parse_constructor( specifiers ); + CodeConstructor result = parser_parse_constructor( specifiers ); return result; } CodeDestructor parse_destructor( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; // TODO(Ed): Destructors can have prefix attributes // TODO(Ed): Destructors can have virtual Context.Tokens = toks; - CodeDestructor result = parse_destructor(); + CodeDestructor result = parser_parse_destructor(NullCode); return result; } CodeEnum parse_enum( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) { - Context.pop(); - return CodeInvalid; + parser_pop(& Context); + return InvalidCode; } Context.Tokens = toks; - return parse_enum(); + return parser_parse_enum( parser_not_inplace_def); } CodeBody parse_export_body( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_export_body(); + return parser_parse_export_body(); } CodeExtern parse_extern_link( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_extern_link(); + return parser_parse_extern_link(); } CodeFriend parse_friend( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_friend(); + return parser_parse_friend(); } CodeFn parse_function( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return (CodeFn) parse_function(); + return (CodeFn) parser_parse_function(); } CodeBody parse_global_body( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; push_scope(); - CodeBody result = parse_global_nspace( ECode::Global_Body ); - Context.pop(); + CodeBody result = parse_global_nspace( CT_Global_Body ); + parser_pop(& Context); return result; } CodeNS parse_namespace( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_namespace(); + return parser_parse_namespace(); } CodeOperator parse_operator( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return (CodeOperator) parse_operator(); + return (CodeOperator) parser_parse_operator(); } CodeOpCast parse_operator_cast( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_operator_cast(); + return parser_parse_operator_cast(NullCode); } CodeStruct parse_struct( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; push_scope(); - CodeStruct result = (CodeStruct) parse_class_struct( TokType::Decl_Struct ); - Context.pop(); + CodeStruct result = (CodeStruct) parse_class_struct( Tok_Decl_Struct, parser_not_inplace_def ); + parser_pop(& Context); return result; } CodeTemplate parse_template( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_template(); + return parser_parse_template(); } -CodeType parse_type( StrC def ) +CodeTypename parse_type( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_type(); + return parser_parse_type( parser_not_from_template, nullptr); } CodeTypedef parse_typedef( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_typedef(); + return parser_parse_typedef(); } CodeUnion parse_union( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_union(); + return parser_parse_union( parser_not_inplace_def); } CodeUsing parse_using( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_using(); + return parser_parse_using(); } CodeVar parse_variable( StrC def ) { + GEN_USING_NS_PARSER; check_parse_args( def ); - using namespace parser; TokArray toks = lex( def ); if ( toks.Arr == nullptr ) - return CodeInvalid; + return InvalidCode; Context.Tokens = toks; - return parse_variable(); + return parser_parse_variable(); } // Undef helper macros -# undef check_parse_args -# undef currtok -# undef prevtok -# undef nexttok -# undef eat -# undef left -# undef check -# undef push_scope +#undef check_parse_args +#undef currtok_noskip +#undef currtok +#undef peektok +#undef prevtok +#undef nexttok +#undef nexttok_noskip +#undef eat +#undef left +#undef check +#undef push_scope +#undef def_assign + +// Here for C Variant +#undef lex_dont_skip_formatting +#undef lex_skip_formatting + +#undef parser_inplace_def +#undef parser_not_inplace_def +#undef parser_dont_consume_braces +#undef parser_consume_braces +#undef parser_not_from_template +#undef parser_use_parenthesis +#undef parser_strip_formatting_dont_preserve_newlines diff --git a/project/components/interface.untyped.cpp b/base/components/interface.untyped.cpp similarity index 69% rename from project/components/interface.untyped.cpp rename to base/components/interface.untyped.cpp index 9eacf1b..d430656 100644 --- a/project/components/interface.untyped.cpp +++ b/base/components/interface.untyped.cpp @@ -6,18 +6,16 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) { char const* buf_begin = buf; - ssize remaining = buf_size; + ssize remaining = buf_size; local_persist - Arena tok_map_arena; + TokenMap_FixedArena tok_map_arena; + fixed_arena_init( & tok_map_arena); - HashTable tok_map; + local_persist + StringTable tok_map; { - local_persist - char tok_map_mem[ TokenFmt_TokenMap_MemSize ]; - - tok_map_arena = Arena::init_from_memory( tok_map_mem, sizeof(tok_map_mem) ); - tok_map = HashTable::init( tok_map_arena ); + tok_map = hashtable_init(StrC, fixed_arena_allocator_info(& tok_map_arena) ); s32 left = num_tokens - 1; @@ -27,8 +25,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) StrC value = va_arg( va, StrC ); u32 key = crc32( token, str_len(token) ); - - tok_map.set( key, value ); + hashtable_set( tok_map, key, value ); } } @@ -64,7 +61,7 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) char const* token = fmt + 1; u32 key = crc32( token, tok_len ); - StrC* value = tok_map.get( key ); + StrC* value = hashtable_get(tok_map, key ); if ( value ) { @@ -94,8 +91,8 @@ ssize token_fmt_va( char* buf, usize buf_size, s32 num_tokens, va_list va ) } } - tok_map.clear(); - tok_map_arena.free(); + hashtable_clear(tok_map); + fixed_arena_free(& tok_map_arena); ssize result = buf_size - remaining; @@ -107,19 +104,19 @@ Code untyped_str( StrC content ) if ( content.Len == 0 ) { log_failure( "untyped_str: empty string" ); - return CodeInvalid; + return InvalidCode; } Code result = make_code(); result->Name = get_cached_string( content ); - result->Type = ECode::Untyped; + result->Type = CT_Untyped; result->Content = result->Name; - if ( result->Name == nullptr ) + if ( result->Name.Len == 0 ) { log_failure( "untyped_str: could not cache string" ); - return CodeInvalid; + return InvalidCode; } return result; @@ -130,7 +127,7 @@ Code untyped_fmt( char const* fmt, ...) if ( fmt == nullptr ) { log_failure( "untyped_fmt: null format string" ); - return CodeInvalid; + return InvalidCode; } local_persist thread_local @@ -141,47 +138,52 @@ Code untyped_fmt( char const* fmt, ...) ssize length = str_fmt_va(buf, GEN_PRINTF_MAXLEN, fmt, va); va_end(va); + StrC buf_str = { str_len_capped(fmt, MaxNameLength), fmt }; + StrC uncapped_str = { length, buf }; + Code result = make_code(); - result->Name = get_cached_string( { str_len(fmt, MaxNameLength), fmt } ); - result->Type = ECode::Untyped; - result->Content = get_cached_string( { length, buf } ); + result->Name = get_cached_string( buf_str ); + result->Type = CT_Untyped; + result->Content = get_cached_string( uncapped_str ); - if ( result->Name == nullptr ) + if ( result->Name.Len == 0 ) { log_failure( "untyped_fmt: could not cache string" ); - return CodeInvalid; + return InvalidCode; } return result; } -Code untyped_token_fmt( s32 num_tokens, ... ) +Code untyped_token_fmt( s32 num_tokens, char const* fmt, ... ) { if ( num_tokens == 0 ) { log_failure( "untyped_token_fmt: zero tokens" ); - return CodeInvalid; + return InvalidCode; } local_persist thread_local char buf[GEN_PRINTF_MAXLEN] = { 0 }; va_list va; - va_start(va, num_tokens); + va_start(va, fmt); ssize length = token_fmt_va(buf, GEN_PRINTF_MAXLEN, num_tokens, va); va_end(va); + StrC buf_str = { length, buf }; + Code result = make_code(); - result->Name = get_cached_string( { length, buf } ); - result->Type = ECode::Untyped; + result->Name = get_cached_string( buf_str ); + result->Type = CT_Untyped; result->Content = result->Name; - if ( result->Name == nullptr ) + if ( result->Name.Len == 0 ) { log_failure( "untyped_fmt: could not cache string" ); - return CodeInvalid; + return InvalidCode; } return result; diff --git a/project/components/interface.upfront.cpp b/base/components/interface.upfront.cpp similarity index 58% rename from project/components/interface.upfront.cpp rename to base/components/interface.upfront.cpp index f0ca08f..bab9686 100644 --- a/project/components/interface.upfront.cpp +++ b/base/components/interface.upfront.cpp @@ -5,59 +5,58 @@ #pragma region Upfront -enum class OpValidateResult : u32 +enum OpValidateResult : u32 { - Fail, - Global, - Member + OpValResult_Fail, + OpValResult_Global, + OpValResult_Member }; -OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeType ret_type, CodeSpecifiers specifier ) +internal neverinline +OpValidateResult operator__validate( Operator op, CodeParams params_code, CodeTypename ret_type, CodeSpecifiers specifier ) { - using namespace EOperator; - - if ( op == EOperator::Invalid ) + if ( op == Op_Invalid ) { log_failure("gen::def_operator: op cannot be invalid"); - return OpValidateResult::Fail; + return OpValResult_Fail; } #pragma region Helper Macros -# define check_params() \ - if ( ! params_code ) \ - { \ - log_failure("gen::def_operator: params is null and operator%s requires it", to_str(op)); \ - return OpValidateResult::Fail; \ - } \ - if ( params_code->Type != ECode::Parameters ) \ - { \ - log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); \ - return OpValidateResult::Fail; \ +# define check_params() \ + if ( ! params_code ) \ + { \ + log_failure("gen::def_operator: params is null and operator%s requires it", operator_to_str(op)); \ + return OpValResult_Fail; \ + } \ + if ( params_code->Type != CT_Parameters ) \ + { \ + log_failure("gen::def_operator: params is not of Parameters type - %s", code_debug_str( cast(Code, params_code))); \ + return OpValResult_Fail; \ } -# define check_param_eq_ret() \ - if ( ! is_member_symbol && ! params_code->ValueType.is_equal( ret_type) ) \ - { \ - log_failure("gen::def_operator: operator%s requires first parameter to equal return type\n" \ - "param types: %s\n" \ - "return type: %s", \ - to_str(op).Ptr, \ - params_code.debug_str(), \ - ret_type.debug_str() \ - ); \ - return OpValidateResult::Fail; \ +# define check_param_eq_ret() \ + if ( ! is_member_symbol && ! code_is_equal(cast(Code, params_code->ValueType), cast(Code, ret_type)) ) \ + { \ + log_failure("gen::def_operator: operator%s requires first parameter to equal return type\n" \ + "param types: %s\n" \ + "return type: %s", \ + operator_to_str(op).Ptr, \ + code_debug_str(cast(Code, params_code)), \ + code_debug_str(cast(Code, ret_type)) \ + ); \ + return OpValResult_Fail; \ } #pragma endregion Helper Macros if ( ! ret_type ) { - log_failure("gen::def_operator: ret_type is null but is required by operator%s", to_str(op)); + log_failure("gen::def_operator: ret_type is null but is required by operator%s", operator_to_str(op)); } - if ( ret_type->Type != ECode::Typename ) + if ( ret_type->Type != CT_Typename ) { - log_failure("gen::def_operator: ret_type is not of typename type - %s", ret_type.debug_str()); - return OpValidateResult::Fail; + log_failure("gen::def_operator: ret_type is not of typename type - %s", code_debug_str(cast(Code, ret_type))); + return OpValResult_Fail; } bool is_member_symbol = false; @@ -65,32 +64,32 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy switch ( op ) { # define specs( ... ) num_args( __VA_ARGS__ ), __VA_ARGS__ - case Assign: + case Op_Assign: check_params(); if ( params_code->NumEntries > 1 ) { log_failure("gen::def_operator: " "operator%s does not support non-member definition (more than one parameter provided) - %s", - to_str(op), - params_code.debug_str() + operator_to_str(op), + code_debug_str(cast(Code, params_code)) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } is_member_symbol = true; break; - case Assign_Add: - case Assign_Subtract: - case Assign_Multiply: - case Assign_Divide: - case Assign_Modulo: - case Assign_BAnd: - case Assign_BOr: - case Assign_BXOr: - case Assign_LShift: - case Assign_RShift: + case Op_Assign_Add: + case Op_Assign_Subtract: + case Op_Assign_Multiply: + case Op_Assign_Divide: + case Op_Assign_Modulo: + case Op_Assign_BAnd: + case Op_Assign_BOr: + case Op_Assign_BXOr: + case Op_Assign_LShift: + case Op_Assign_RShift: check_params(); if ( params_code->NumEntries == 1 ) @@ -102,32 +101,32 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy if (params_code->NumEntries > 2 ) { log_failure("gen::def_operator: operator%s may not be defined with more than two parametes - param count; %d\n%s" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries - , params_code.debug_str() + , code_debug_str(cast(Code, params_code)) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case Increment: - case Decrement: + case Op_Increment: + case Op_Decrement: // If its not set, it just means its a prefix member op. if ( params_code ) { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { log_failure("gen::def_operator: operator%s params code provided is not of Parameters type - %s" - , to_str(op) - , params_code.debug_str() + , operator_to_str(op) + , code_debug_str(cast(Code, params_code)) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } switch ( params_code->NumEntries ) { case 1: - if ( params_code->ValueType.is_equal( t_int ) ) + if ( code_is_equal((Code)params_code->ValueType, (Code)t_int ) ) is_member_symbol = true; else @@ -137,69 +136,69 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy case 2: check_param_eq_ret(); - if ( ! params_code.get(1).is_equal( t_int ) ) + if ( ! code_is_equal((Code)params_get(params_code, 1), (Code)t_int ) ) { log_failure("gen::def_operator: " "operator%s requires second parameter of non-member definition to be int for post-decrement", - to_str(op) + operator_to_str(op) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; default: log_failure("gen::def_operator: operator%s recieved unexpected number of parameters recived %d instead of 0-2" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } break; - case Unary_Plus: - case Unary_Minus: + case Op_Unary_Plus: + case Op_Unary_Minus: if ( ! params_code ) is_member_symbol = true; else { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); - return OpValidateResult::Fail; + log_failure("gen::def_operator: params is not of Parameters type - %s", code_debug_str((Code)params_code)); + return OpValResult_Fail; } - if ( params_code->ValueType.is_equal( ret_type ) ) + if ( code_is_equal((Code)params_code->ValueType, (Code)ret_type ) ) { log_failure("gen::def_operator: " "operator%s is non-member symbol yet first paramter does not equal return type\n" "param type: %s\n" "return type: %s\n" - , params_code.debug_str() - , ret_type.debug_str() + , code_debug_str((Code)params_code) + , code_debug_str((Code)ret_type) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } if ( params_code->NumEntries > 1 ) { log_failure("gen::def_operator: operator%s may not have more than one parameter - param count: %d" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } break; - case BNot: + case Op_BNot: { // Some compilers let you do this... #if 0 if ( ! ret_type.is_equal( t_bool) ) { - log_failure( "gen::def_operator: return type is not a boolean - %s", params_code.debug_str() ); + log_failure( "gen::def_operator: return type is not a boolean - %s", code_debug_str(params_code) ); return OpValidateResult::Fail; } #endif @@ -209,35 +208,35 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy else { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure( "gen::def_operator: params is not of Parameters type - %s", params_code.debug_str() ); - return OpValidateResult::Fail; + log_failure( "gen::def_operator: params is not of Parameters type - %s", code_debug_str((Code)params_code) ); + return OpValResult_Fail; } if ( params_code->NumEntries > 1 ) { log_failure( - "gen::def_operator: operator%s may not have more than one parameter - param count: %d", - to_str( op ), - params_code->NumEntries + "gen::def_operator: operator%s may not have more than one parameter - param count: %d", + operator_to_str( op ), + params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } break; } - case Add: - case Subtract: - case Multiply: - case Divide: - case Modulo: - case BAnd: - case BOr: - case BXOr: - case LShift: - case RShift: + case Op_Add: + case Op_Subtract: + case Op_Multiply: + case Op_Divide: + case Op_Modulo: + case Op_BAnd: + case Op_BOr: + case Op_BXOr: + case Op_LShift: + case Op_RShift: check_params(); switch ( params_code->NumEntries ) @@ -247,68 +246,68 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy break; case 2: - if ( ! params_code->ValueType.is_equal( ret_type ) ) + if ( ! code_is_equal((Code)params_code->ValueType, (Code)ret_type ) ) { log_failure("gen::def_operator: " "operator%s is non-member symbol yet first paramter does not equal return type\n" "param type: %s\n" "return type: %s\n" - , params_code.debug_str() - , ret_type.debug_str() + , code_debug_str((Code)params_code) + , code_debug_str((Code)ret_type) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; default: log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-2" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case UnaryNot: + case Op_UnaryNot: if ( ! params_code ) is_member_symbol = true; else { - if ( params_code->Type != ECode::Parameters ) + if ( params_code->Type != CT_Parameters ) { - log_failure("gen::def_operator: params is not of Parameters type - %s", params_code.debug_str()); - return OpValidateResult::Fail; + log_failure("gen::def_operator: params is not of Parameters type - %s", code_debug_str((Code)params_code)); + return OpValResult_Fail; } if ( params_code->NumEntries != 1 ) { log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } } - if ( ! ret_type.is_equal( t_bool )) + if ( ! code_is_equal((Code)ret_type, (Code)t_bool )) { log_failure("gen::def_operator: operator%s return type must be of type bool - %s" - , to_str(op) - , ret_type.debug_str() + , operator_to_str(op) + , code_debug_str((Code)ret_type) ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case LAnd: - case LOr: - case LEqual: - case LNot: - case Lesser: - case Greater: - case LesserEqual: - case GreaterEqual: + case Op_LAnd: + case Op_LOr: + case Op_LEqual: + case Op_LNot: + case Op_Lesser: + case Op_Greater: + case Op_LesserEqual: + case Op_GreaterEqual: check_params(); switch ( params_code->NumEntries ) @@ -322,23 +321,23 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy default: log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 1-2" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } break; - case Indirection: - case AddressOf: - case MemberOfPointer: + case Op_Indirection: + case Op_AddressOf: + case Op_MemberOfPointer: if ( params_code && params_code->NumEntries > 1) { log_failure("gen::def_operator: operator%s recieved unexpected number of paramters recived %d instead of 0-1" - , to_str(op) + , operator_to_str(op) , params_code->NumEntries ); - return OpValidateResult::Fail; + return OpValResult_Fail; } else { @@ -346,28 +345,28 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy } break; - case PtrToMemOfPtr: + case Op_PtrToMemOfPtr: if ( params_code ) { - log_failure("gen::def_operator: operator%s expects no paramters - %s", to_str(op), params_code.debug_str()); - return OpValidateResult::Fail; + log_failure("gen::def_operator: operator%s expects no paramters - %s", operator_to_str(op), code_debug_str((Code)params_code)); + return OpValResult_Fail; } break; - case Subscript: - case FunctionCall: - case Comma: + case Op_Subscript: + case Op_FunctionCall: + case Op_Comma: check_params(); break; - case New: - case Delete: + case Op_New: + case Op_Delete: // This library doesn't support validating new and delete yet. break; # undef specs } - return is_member_symbol ? OpValidateResult::Member : OpValidateResult::Global; + return is_member_symbol ? OpValResult_Member : OpValResult_Global; # undef check_params # undef check_ret_type # undef check_param_eq_ret @@ -381,21 +380,21 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy if ( Name_.Len <= 0 ) \ { \ log_failure( "gen::" stringize(Context_) ": Invalid name length provided - %d", Name_.Len ); \ - return CodeInvalid; \ + return InvalidCode; \ } \ \ if ( Name_.Ptr == nullptr ) \ { \ log_failure( "gen::" stringize(Context_) ": name is null" ); \ - return CodeInvalid; \ + return InvalidCode; \ } \ } #define null_check( Context_, Code_ ) \ - if ( ! Code_ ) \ + if ( Code_ == nullptr ) \ { \ log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ - return CodeInvalid; \ + return InvalidCode; \ } #define null_or_invalid_check( Context_, Code_ ) \ @@ -403,22 +402,21 @@ OpValidateResult operator__validate( OperatorT op, CodeParam params_code, CodeTy if ( ! Code_ ) \ { \ log_failure( "gen::" stringize(Context_) ": " stringize(Code_) " provided is null" ); \ - return CodeInvalid; \ + return InvalidCode; \ } \ \ if ( Code_->is_invalid() ) \ { \ log_failure("gen::" stringize(Context_) ": " stringize(Code_) " provided is invalid" ); \ - return CodeInvalid; \ + return InvalidCode; \ } \ } #define not_implemented( Context_ ) \ log_failure( "gen::%s: This function is not implemented" ); \ - return CodeInvalid; + return InvalidCode; #pragma endregion Helper Marcos - /* The implementaiton of the upfront constructors involves doing three things: * Validate the arguments given to construct the intended type of AST is valid. @@ -436,12 +434,12 @@ CodeAttributes def_attributes( StrC content ) if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_attributes: Invalid attributes provided" ); - return CodeInvalid; + return InvalidCode; } Code result = make_code(); - result->Type = ECode::PlatformAttributes; + result->Type = CT_PlatformAttributes; result->Name = get_cached_string( content ); result->Content = result->Name; @@ -453,12 +451,12 @@ CodeComment def_comment( StrC content ) if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + return InvalidCode; } static char line[ MaxCommentLineLength ]; - String cmt_formatted = String::make_reserve( GlobalAllocator, kilobytes(1) ); + String cmt_formatted = string_make_reserve( GlobalAllocator, kilobytes(1) ); char const* end = content.Ptr + content.Len; char const* scanner = content.Ptr; s32 curr = 0; @@ -474,35 +472,39 @@ CodeComment def_comment( StrC content ) length++; str_copy( line, scanner, length ); - cmt_formatted.append_fmt( "//%.*s", length, line ); + string_append_fmt(& cmt_formatted, "//%.*s", length, line ); mem_set( line, 0, MaxCommentLineLength ); scanner += length; } while ( scanner <= end ); - if ( cmt_formatted.back() != '\n' ) - cmt_formatted.append( "\n" ); + if ( * string_back(cmt_formatted) != '\n' ) + string_append_strc( & cmt_formatted, txt("\n") ); + + StrC name = { string_length(cmt_formatted), cmt_formatted }; Code result = make_code(); - result->Type = ECode::Comment; - result->Name = get_cached_string( cmt_formatted ); + result->Type = CT_Comment; + result->Name = get_cached_string( name ); result->Content = result->Name; - cmt_formatted.free(); + string_free(& cmt_formatted); return (CodeComment) result; } -CodeConstructor def_constructor( CodeParam params, Code initializer_list, Code body ) +CodeConstructor def_constructor( Opts_def_constructor p ) { - using namespace ECode; + CodeParams params = p.params; + Code initializer_list = p.initializer_list; + Code body = p.body; - if ( params && params->Type != Parameters ) + if ( params && params->Type != CT_Parameters ) { - log_failure("gen::def_constructor: params must be of Parameters type - %s", params.debug_str()); - return CodeInvalid; + log_failure("gen::def_constructor: params must be of Parameters type - %s", code_debug_str((Code)params)); + return InvalidCode; } CodeConstructor @@ -522,47 +524,48 @@ CodeConstructor def_constructor( CodeParam params, Code initializer_list, Code b { switch ( body->Type ) { - case Function_Body: - case Untyped: + case CT_Function_Body: + case CT_Untyped: break; default: - log_failure("gen::def_constructor: body must be either of Function_Body or Untyped type - %s", body.debug_str()); - return CodeInvalid; + log_failure("gen::def_constructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(body)); + return InvalidCode; } - result->Type = Constructor; + result->Type = CT_Constructor; result->Body = body; } else { - result->Type = Constructor_Fwd; + result->Type = CT_Constructor_Fwd; } return result; } -CodeClass def_class( StrC name - , Code body - , CodeType parent, AccessSpec parent_access - , CodeAttributes attributes - , ModuleFlag mflags - , CodeType* interfaces, s32 num_interfaces ) +CodeClass def_class( StrC name, Opts_def_struct p ) { - using namespace ECode; - name_check( def_class, name ); - if ( attributes && attributes->Type != PlatformAttributes ) + CodeBody body = p.body; + CodeTypename parent = p.parent; + AccessSpec parent_access = p.parent_access; + CodeAttributes attributes = p.attributes; + ModuleFlag mflags = p.mflags; + CodeTypename* interfaces = p.interfaces; + s32 num_interfaces = p.num_interfaces; + + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_class: attributes was not a 'PlatformAttributes' type: %s", code_debug_str(attributes) ); + return InvalidCode; } - if ( parent && ( parent->Type != Class && parent->Type != Struct && parent->Type != Typename && parent->Type != Untyped ) ) + if ( parent && ( parent->Type != CT_Class && parent->Type != CT_Struct && parent->Type != CT_Typename && parent->Type != CT_Untyped ) ) { - log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", parent.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_class: parent provided is not type 'Class', 'Struct', 'Typeanme', or 'Untyped': %s", code_debug_str(parent) ); + return InvalidCode; } CodeClass @@ -574,22 +577,22 @@ CodeClass def_class( StrC name { switch ( body->Type ) { - case Class_Body: - case Untyped: + case CT_Class_Body: + case CT_Untyped: break; default: - log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", body.debug_str()); - return CodeInvalid; + log_failure("gen::def_class: body must be either of Class_Body or Untyped type - %s", code_debug_str(body)); + return InvalidCode; } - result->Type = Class; + result->Type = CT_Class; result->Body = body; - result->Body->Parent = result; // TODO(Ed): Review this? + result->Body->Parent = cast(Code, result); // TODO(Ed): Review this? } else { - result->Type = Class_Fwd; + result->Type = CT_Class_Fwd; } if ( attributes ) @@ -605,17 +608,15 @@ CodeClass def_class( StrC name { for (s32 idx = 0; idx < num_interfaces; idx++ ) { - result.add_interface( interfaces[idx] ); + class_add_interface(result, interfaces[idx] ); } } return result; } -CodeDefine def_define( StrC name, StrC content ) +CodeDefine def_define( StrC name, StrC content, Opts_def_define p ) { - using namespace ECode; - name_check( def_define, name ); // Defines can be empty definitions @@ -623,32 +624,44 @@ CodeDefine def_define( StrC name, StrC content ) if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_define: Invalid value provided" ); - return CodeInvalid; + return InvalidCode; } #endif CodeDefine result = (CodeDefine) make_code(); - result->Type = Preprocess_Define; + result->Type = CT_Preprocess_Define; result->Name = get_cached_string( name ); if ( content.Len <= 0 || content.Ptr == nullptr ) { result->Content = get_cached_string( txt("") ); } else - result->Content = get_cached_string( content ); + result->Content = get_cached_string( string_to_strc(string_fmt_buf(GlobalAllocator, "%SC\n", content)) ); + b32 append_preprocess_defines = ! p.dont_append_preprocess_defines; + if ( append_preprocess_defines ) { + // Add the define to PreprocessorDefines for usage in parsing + s32 lex_id_len = 0; + for (; lex_id_len < result->Name.Len; ++ lex_id_len ) { + if ( result->Name.Ptr[lex_id_len] == '(' ) + break; + } + StrC lex_id = { lex_id_len, result->Name.Ptr }; + array_append(PreprocessorDefines, lex_id ); + } return result; } -CodeDestructor def_destructor( Code body, CodeSpecifiers specifiers ) +CodeDestructor def_destructor( Opts_def_destructor p ) { - using namespace ECode; + Code body = p.body; + CodeSpecifiers specifiers = p.specifiers; - if ( specifiers && specifiers->Type != Specifiers ) + if ( specifiers && specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_destructor: specifiers was not a 'Specifiers' type: %s", code_debug_str(specifiers) ); + return InvalidCode; } CodeDestructor result = (CodeDestructor) make_code(); @@ -660,45 +673,47 @@ CodeDestructor def_destructor( Code body, CodeSpecifiers specifiers ) { switch ( body->Type ) { - case Function_Body: - case Untyped: + case CT_Function_Body: + case CT_Untyped: break; default: - log_failure("gen::def_destructor: body must be either of Function_Body or Untyped type - %s", body.debug_str()); - return CodeInvalid; + log_failure("gen::def_destructor: body must be either of Function_Body or Untyped type - %s", code_debug_str(body)); + return InvalidCode; } - result->Type = Destructor; + result->Type = CT_Destructor; result->Body = body; } else { - result->Type = Destructor_Fwd; + result->Type = CT_Destructor_Fwd; } return result; } -CodeEnum def_enum( StrC name - , Code body, CodeType type - , EnumT specifier, CodeAttributes attributes - , ModuleFlag mflags ) +CodeEnum def_enum( StrC name, Opts_def_enum p ) { - using namespace ECode; + CodeBody body = p.body; + CodeTypename type = p.type; + EnumT specifier = p.specifier; + CodeAttributes attributes = p.attributes; + ModuleFlag mflags = p.mflags; + Code type_macro = p.type_macro; name_check( def_enum, name ); - if ( type && type->Type != Typename ) + if ( type && type->Type != CT_Typename ) { - log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_enum: enum underlying type provided was not of type Typename: %s", code_debug_str((Code)type) ); + return InvalidCode; } - if ( attributes && attributes->Type != PlatformAttributes ) + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_enum: attributes was not a 'PlatformAttributes' type: %s", code_debug_str((Code)attributes) ); + return InvalidCode; } CodeEnum @@ -710,24 +725,24 @@ CodeEnum def_enum( StrC name { switch ( body->Type ) { - case Enum_Body: - case Untyped: + case CT_Enum_Body: + case CT_Untyped: break; default: - log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", body.debug_str()); - return CodeInvalid; + log_failure( "gen::def_enum: body must be of Enum_Body or Untyped type %s", code_debug_str(body)); + return InvalidCode; } - result->Type = specifier == EnumClass ? - Enum_Class : Enum; + result->Type = specifier == EnumDecl_Class ? + CT_Enum_Class : CT_Enum; result->Body = body; } else { - result->Type = specifier == EnumClass ? - Enum_Class_Fwd : Enum_Fwd; + result->Type = specifier == EnumDecl_Class ? + CT_Enum_Class_Fwd : CT_Enum_Fwd; } if ( attributes ) @@ -737,10 +752,14 @@ CodeEnum def_enum( StrC name { result->UnderlyingType = type; } - else if ( result->Type != Enum_Class_Fwd && result->Type != Enum_Fwd ) + else if ( type_macro ) + { + result->UnderlyingTypeMacro = type_macro; + } + else if ( result->Type != CT_Enum_Class_Fwd && result->Type != CT_Enum_Fwd ) { log_failure( "gen::def_enum: enum forward declaration must have an underlying type" ); - return CodeInvalid; + return InvalidCode; } return result; @@ -751,34 +770,32 @@ CodeExec def_execution( StrC content ) if ( content.Len <= 0 || content.Ptr == nullptr ) { log_failure( "gen::def_execution: Invalid execution provided" ); - return CodeInvalid; + return InvalidCode; } Code result = make_code(); - result->Type = ECode::Execution; + result->Type = CT_Execution; result->Name = get_cached_string( content ); result->Content = result->Name; return (CodeExec) result; } -CodeExtern def_extern_link( StrC name, Code body ) +CodeExtern def_extern_link( StrC name, CodeBody body ) { - using namespace ECode; - name_check( def_extern_linkage, name ); null_check( def_extern_linkage, body ); - if ( body->Type != Extern_Linkage_Body && body->Type != Untyped ) + if ( body->Type != CT_Extern_Linkage_Body && body->Type != CT_Untyped ) { - log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", body->debug_str()); - return CodeInvalid; + log_failure("gen::def_extern_linkage: body is not of extern_linkage or untyped type %s", code_debug_str(body)); + return InvalidCode; } CodeExtern result = (CodeExtern)make_code(); - result->Type = Extern_Linkage; + result->Type = CT_Extern_Linkage; result->Name = get_cached_string( name ); result->Body = body; @@ -787,67 +804,67 @@ CodeExtern def_extern_link( StrC name, Code body ) CodeFriend def_friend( Code declaration ) { - using namespace ECode; - null_check( def_friend, declaration ); switch ( declaration->Type ) { - case Class_Fwd: - case Function_Fwd: - case Operator_Fwd: - case Struct_Fwd: - case Class: - case Function: - case Operator: - case Struct: + case CT_Class_Fwd: + case CT_Function_Fwd: + case CT_Operator_Fwd: + case CT_Struct_Fwd: + case CT_Class: + case CT_Function: + case CT_Operator: + case CT_Struct: break; default: - log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", declaration->debug_str()); - return CodeInvalid; + log_failure("gen::def_friend: requires declartion to have class, function, operator, or struct - %s", code_debug_str(declaration)); + return InvalidCode; } CodeFriend result = (CodeFriend) make_code(); - result->Type = Friend; + result->Type = CT_Friend; result->Declaration = declaration; return result; } -CodeFn def_function( StrC name - , CodeParam params , CodeType ret_type, Code body - , CodeSpecifiers specifiers, CodeAttributes attributes - , ModuleFlag mflags ) +CodeFn def_function( StrC name, Opts_def_function p ) { - using namespace ECode; + CodeParams params = p.params; + CodeTypename ret_type = p.ret_type; + CodeBody body = p.body; + CodeSpecifiers specifiers = p.specs; + CodeAttributes attributes = p.attrs; + ModuleFlag mflags = p.mflags; name_check( def_function, name ); - if ( params && params->Type != Parameters ) + if ( params && params->Type != CT_Parameters ) { - log_failure( "gen::def_function: params was not a `Parameters` type: %s", params.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_function: params was not a `Parameters` type: %s", code_debug_str(params) ); + return InvalidCode; } - if ( ret_type && ret_type->Type != Typename ) + if ( ret_type && ret_type->Type != CT_Typename ) { - log_failure( "gen::def_function: ret_type was not a Typename: %s", ret_type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_function: ret_type was not a Typename: %s", code_debug_str(ret_type) ); + return InvalidCode; } - if ( specifiers && specifiers->Type != Specifiers ) + if ( specifiers && specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_function: specifiers was not a `Specifiers` type: %s", code_debug_str(specifiers) ); + return InvalidCode; } - if ( attributes && attributes->Type != PlatformAttributes ) + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_function: attributes was not a `PlatformAttributes` type: %s", code_debug_str(attributes) ); + return InvalidCode; } CodeFn @@ -859,24 +876,24 @@ CodeFn def_function( StrC name { switch ( body->Type ) { - case Function_Body: - case Execution: - case Untyped: + case CT_Function_Body: + case CT_Execution: + case CT_Untyped: break; default: { - log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); - return CodeInvalid; + log_failure("gen::def_function: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(body)); + return InvalidCode; } } - result->Type = Function; + result->Type = CT_Function; result->Body = body; } else { - result->Type = Function_Fwd; + result->Type = CT_Function_Fwd; } if ( attributes ) @@ -900,100 +917,102 @@ CodeFn def_function( StrC name return result; } -CodeInclude def_include( StrC path, bool foreign ) +CodeInclude def_include( StrC path, Opts_def_include p ) { if ( path.Len <= 0 || path.Ptr == nullptr ) { log_failure( "gen::def_include: Invalid path provided - %d" ); - return CodeInvalid; + return InvalidCode; } - StrC content = foreign ? - to_str( str_fmt_buf( "<%.*s>", path.Len, path.Ptr )) - : to_str( str_fmt_buf( "\"%.*s\"", path.Len, path.Ptr )); + String content = p.foreign ? + string_fmt_buf( GlobalAllocator, "<%.*s>", path.Len, path.Ptr ) + : string_fmt_buf( GlobalAllocator, "\"%.*s\"", path.Len, path.Ptr ); Code result = make_code(); - result->Type = ECode::Preprocess_Include; - result->Name = get_cached_string( content ); + result->Type = CT_Preprocess_Include; + result->Name = get_cached_string( string_to_strc(content) ); result->Content = result->Name; return (CodeInclude) result; } -CodeModule def_module( StrC name, ModuleFlag mflags ) +CodeModule def_module( StrC name, Opts_def_module p ) { name_check( def_module, name ); Code result = make_code(); - result->Type = ECode::Module; + result->Type = CT_Module; result->Name = get_cached_string( name ); result->Content = result->Name; - result->ModuleFlags = mflags; + result->ModuleFlags = p.mflags; return (CodeModule) result; } -CodeNS def_namespace( StrC name, Code body, ModuleFlag mflags ) +CodeNS def_namespace( StrC name, CodeBody body, Opts_def_namespace p ) { - using namespace ECode; - name_check( def_namespace, name ); - null_check( def_namespace, body ); + null_check( def_namespace, body); - if ( body->Type != Namespace_Body && body->Type != Untyped ) + if ( body && body->Type != CT_Namespace_Body && body->Type != CT_Untyped ) { - log_failure("gen::def_namespace: body is not of namespace or untyped type %s", body.debug_str()); - return CodeInvalid; + log_failure("gen::def_namespace: body is not of namespace or untyped type %s", code_debug_str(body)); + return InvalidCode; } CodeNS result = (CodeNS) make_code(); - result->Type = Namespace; + result->Type = CT_Namespace; result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; + result->ModuleFlags = p.mflags; result->Body = body; - return result; } -CodeOperator def_operator( OperatorT op, StrC nspace - , CodeParam params_code, CodeType ret_type, Code body - , CodeSpecifiers specifiers, CodeAttributes attributes - , ModuleFlag mflags ) +CodeOperator def_operator( Operator op, StrC nspace, Opts_def_operator p ) { - using namespace ECode; + CodeParams params_code = p.params; + CodeTypename ret_type = p.ret_type; + CodeBody body = p.body; + CodeSpecifiers specifiers = p.specifiers; + CodeAttributes attributes = p.attributes; + ModuleFlag mflags = p.mflags; - if ( attributes && attributes->Type != PlatformAttributes ) + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_operator: PlatformAttributes was provided but its not of attributes type: %s", code_debug_str(attributes) ); + return InvalidCode; } - if ( specifiers && specifiers->Type != Specifiers ) + if ( specifiers && specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_operator: Specifiers was provided but its not of specifiers type: %s", code_debug_str(specifiers) ); + return InvalidCode; } OpValidateResult check_result = operator__validate( op, params_code, ret_type, specifiers ); - if ( check_result == OpValidateResult::Fail ) + if ( check_result == OpValResult_Fail ) { - return CodeInvalid; + return InvalidCode; } char const* name = nullptr; - StrC op_str = to_str( op ); + StrC op_str = operator_to_str( op ); if ( nspace.Len > 0 ) name = str_fmt_buf( "%.*soperator %.*s", nspace.Len, nspace.Ptr, op_str.Len, op_str.Ptr ); else name = str_fmt_buf( "operator %.*s", op_str.Len, op_str.Ptr ); + + StrC name_resolved = { str_len(name), name }; + CodeOperator result = (CodeOperator) make_code(); - result->Name = get_cached_string( { str_len(name), name } ); + result->Name = get_cached_string( name_resolved ); result->ModuleFlags = mflags; result->Op = op; @@ -1001,27 +1020,27 @@ CodeOperator def_operator( OperatorT op, StrC nspace { switch ( body->Type ) { - case Function_Body: - case Execution: - case Untyped: + case CT_Function_Body: + case CT_Execution: + case CT_Untyped: break; default: { - log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", body->debug_str()); - return CodeInvalid; + log_failure("gen::def_operator: body must be either of Function_Body, Execution, or Untyped type. %s", code_debug_str(body)); + return InvalidCode; } } - result->Type = check_result == OpValidateResult::Global ? - Operator : Operator_Member; + result->Type = check_result == OpValResult_Global ? + CT_Operator : CT_Operator_Member; result->Body = body; } else { - result->Type = check_result == OpValidateResult::Global ? - Operator_Fwd : Operator_Member_Fwd; + result->Type = check_result == OpValResult_Global ? + CT_Operator_Fwd : CT_Operator_Member_Fwd; } if ( attributes ) @@ -1038,34 +1057,36 @@ CodeOperator def_operator( OperatorT op, StrC nspace return result; } -CodeOpCast def_operator_cast( CodeType type, Code body, CodeSpecifiers const_spec ) +CodeOpCast def_operator_cast( CodeTypename type, Opts_def_operator_cast p ) { - using namespace ECode; + CodeBody body = p.body; + CodeSpecifiers const_spec = p.specs; + null_check( def_operator_cast, type ); - if ( type->Type != Typename ) + if ( type->Type != CT_Typename ) { - log_failure( "gen::def_operator_cast: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_operator_cast: type is not a typename - %s", code_debug_str(type) ); + return InvalidCode; } CodeOpCast result = (CodeOpCast) make_code(); if (body) { - result->Type = Operator_Cast; + result->Type = CT_Operator_Cast; - if ( body->Type != Function_Body && body->Type != Execution ) + if ( body->Type != CT_Function_Body && body->Type != CT_Execution ) { - log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", body.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_operator_cast: body is not of function body or execution type - %s", code_debug_str(body) ); + return InvalidCode; } result->Body = body; } else { - result->Type = Operator_Cast_Fwd; + result->Type = CT_Operator_Cast_Fwd; } if ( const_spec ) @@ -1077,34 +1098,32 @@ CodeOpCast def_operator_cast( CodeType type, Code body, CodeSpecifiers const_spe return result; } -CodeParam def_param( CodeType type, StrC name, Code value ) +CodeParams def_param( CodeTypename type, StrC name, Opts_def_param p ) { - using namespace ECode; - name_check( def_param, name ); null_check( def_param, type ); - if ( type->Type != Typename ) + if ( type->Type != CT_Typename ) { - log_failure( "gen::def_param: type is not a typename - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_param: type is not a typename - %s", code_debug_str(type) ); + return InvalidCode; } - if ( value && value->Type != Untyped ) + if ( p.value && p.value->Type != CT_Untyped ) { - log_failure( "gen::def_param: value is not untyped - %s", value.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_param: value is not untyped - %s", code_debug_str(p.value) ); + return InvalidCode; } - CodeParam - result = (CodeParam) make_code(); - result->Type = Parameters; + CodeParams + result = (CodeParams) make_code(); + result->Type = CT_Parameters; result->Name = get_cached_string( name ); result->ValueType = type; - if ( value ) - result->Value = value; + if ( p.value ) + result->Value = p.value; result->NumEntries++; @@ -1113,17 +1132,15 @@ CodeParam def_param( CodeType type, StrC name, Code value ) CodePragma def_pragma( StrC directive ) { - using namespace ECode; - if ( directive.Len <= 0 || directive.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + return InvalidCode; } CodePragma result = (CodePragma) make_code(); - result->Type = Preprocess_Pragma; + result->Type = CT_Preprocess_Pragma; result->Content = get_cached_string( directive ); return result; @@ -1131,12 +1148,10 @@ CodePragma def_pragma( StrC directive ) CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) { - using namespace ECode; - if ( expr.Len <= 0 || expr.Ptr == nullptr ) { log_failure( "gen::def_comment: Invalid comment provided:" ); - return CodeInvalid; + return InvalidCode; } CodePreprocessCond @@ -1145,75 +1160,76 @@ CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr ) switch (type) { - case EPreprocessCond::If: - result->Type = Preprocess_If; + case PreprocessCond_If: + result->Type = CT_Preprocess_If; break; - case EPreprocessCond::IfDef: - result->Type = Preprocess_IfDef; + case PreprocessCond_IfDef: + result->Type = CT_Preprocess_IfDef; break; - case EPreprocessCond::IfNotDef: - result->Type = Preprocess_IfNotDef; + case PreprocessCond_IfNotDef: + result->Type = CT_Preprocess_IfNotDef; break; - case EPreprocessCond::ElIf: - result->Type = Preprocess_ElIf; + case PreprocessCond_ElIf: + result->Type = CT_Preprocess_ElIf; break; } return result; } -CodeSpecifiers def_specifier( SpecifierT spec ) +CodeSpecifiers def_specifier( Specifier spec ) { CodeSpecifiers result = (CodeSpecifiers) make_code(); - result->Type = ECode::Specifiers; - result.append( spec ); + result->Type = CT_Specifiers; + specifiers_append(result, spec ); return result; } -CodeStruct def_struct( StrC name - , Code body - , CodeType parent, AccessSpec parent_access - , CodeAttributes attributes - , ModuleFlag mflags - , CodeType* interfaces, s32 num_interfaces ) +CodeStruct def_struct( StrC name, Opts_def_struct p ) { - using namespace ECode; + CodeBody body = p.body; + CodeTypename parent = p.parent; + AccessSpec parent_access = p.parent_access; + CodeAttributes attributes = p.attributes; + ModuleFlag mflags = p.mflags; + CodeTypename* interfaces = p.interfaces; + s32 num_interfaces = p.num_interfaces; - if ( attributes && attributes->Type != PlatformAttributes ) + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_struct: attributes was not a `PlatformAttributes` type - %s", code_debug_str(cast(Code, attributes)) ); + return InvalidCode; } - if ( parent && parent->Type != Typename ) + if ( parent && parent->Type != CT_Typename ) { - log_failure( "gen::def_struct: parent was not a `Struct` type - %s", parent.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_struct: parent was not a `Struct` type - %s", code_debug_str(parent) ); + return InvalidCode; } - if ( body && body->Type != Struct_Body ) + if ( body && body->Type != CT_Struct_Body ) { - log_failure( "gen::def_struct: body was not a Struct_Body type - %s", body.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_struct: body was not a Struct_Body type - %s", code_debug_str(body) ); + return InvalidCode; } CodeStruct result = (CodeStruct) make_code(); result->ModuleFlags = mflags; - if ( name ) + if ( name.Len ) result->Name = get_cached_string( name ); if ( body ) { - result->Type = Struct; + result->Type = CT_Struct; result->Body = body; } else { - result->Type = Struct_Fwd; + result->Type = CT_Struct_Fwd; } if ( attributes ) @@ -1229,72 +1245,75 @@ CodeStruct def_struct( StrC name { for (s32 idx = 0; idx < num_interfaces; idx++ ) { - result.add_interface( interfaces[idx] ); + struct_add_interface(result, interfaces[idx] ); } } return result; } -CodeTemplate def_template( CodeParam params, Code declaration, ModuleFlag mflags ) +CodeTemplate def_template( CodeParams params, Code declaration, Opts_def_template p ) { null_check( def_template, declaration ); - if ( params && params->Type != ECode::Parameters ) + if ( params && params->Type != CT_Parameters ) { - log_failure( "gen::def_template: params is not of parameters type - %s", params.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_template: params is not of parameters type - %s", code_debug_str(params) ); + return InvalidCode; } switch (declaration->Type ) { - case ECode::Class: - case ECode::Function: - case ECode::Struct: - case ECode::Variable: - case ECode::Using: + case CT_Class: + case CT_Function: + case CT_Struct: + case CT_Variable: + case CT_Using: break; default: - log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", declaration.debug_str() ); + log_failure( "gen::def_template: declaration is not of class, function, struct, variable, or using type - %s", code_debug_str(declaration) ); } CodeTemplate result = (CodeTemplate) make_code(); - result->Type = ECode::Template; - result->ModuleFlags = mflags; + result->Type = CT_Template; + result->ModuleFlags = p.mflags; result->Params = params; result->Declaration = declaration; - return result; } -CodeType def_type( StrC name, Code arrayexpr, CodeSpecifiers specifiers, CodeAttributes attributes ) +CodeTypename def_type( StrC name, Opts_def_type p ) { name_check( def_type, name ); - if ( attributes && attributes->Type != ECode::PlatformAttributes ) + Code arrayexpr = p.arrayexpr; + CodeSpecifiers specifiers = p.specifiers; + CodeAttributes attributes = p.attributes; + + if ( attributes && attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_type: attributes is not of attributes type - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_type: attributes is not of attributes type - %s", code_debug_str((Code)attributes) ); + return InvalidCode; } - if ( specifiers && specifiers->Type != ECode::Specifiers ) + if ( specifiers && specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_type: specifiers is not of specifiers type - %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_type: specifiers is not of specifiers type - %s", code_debug_str((Code)specifiers) ); + return InvalidCode; } - if ( arrayexpr && arrayexpr->Type != ECode::Untyped ) + if ( arrayexpr && arrayexpr->Type != CT_Untyped ) { - log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", arrayexpr->debug_str() ); - return CodeInvalid; + log_failure( "gen::def_type: arrayexpr is not of untyped type - %s", code_debug_str((Code)arrayexpr) ); + return InvalidCode; } - CodeType - result = (CodeType) make_code(); + CodeTypename + result = (CodeTypename) make_code(); result->Name = get_cached_string( name ); - result->Type = ECode::Typename; + result->Type = CT_Typename; if ( attributes ) result->Attributes = attributes; @@ -1305,62 +1324,62 @@ CodeType def_type( StrC name, Code arrayexpr, CodeSpecifiers specifiers, CodeAtt if ( arrayexpr ) result->ArrExpr = arrayexpr; + result->TypeTag = p.type_tag; + return result; } -CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, ModuleFlag mflags ) +CodeTypedef def_typedef( StrC name, Code type, Opts_def_typedef p ) { - using namespace ECode; - null_check( def_typedef, type ); switch ( type->Type ) { - case Class: - case Class_Fwd: - case Enum: - case Enum_Fwd: - case Enum_Class: - case Enum_Class_Fwd: - case Function_Fwd: - case Struct: - case Struct_Fwd: - case Union: - case Typename: + case CT_Class: + case CT_Class_Fwd: + case CT_Enum: + case CT_Enum_Fwd: + case CT_Enum_Class: + case CT_Enum_Class_Fwd: + case CT_Function_Fwd: + case CT_Struct: + case CT_Struct_Fwd: + case CT_Union: + case CT_Typename: break; default: - log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_typedef: type was not a Class, Enum, Function Forward, Struct, Typename, or Union - %s", code_debug_str((Code)type) ); + return InvalidCode; } - if ( attributes && attributes->Type != ECode::PlatformAttributes ) + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_typedef: attributes was not a PlatformAttributes - %s", code_debug_str((Code)p.attributes) ); + return InvalidCode; } // Registering the type. - Code registered_type = def_type( name ); + CodeTypename registered_type = def_type( name ); if ( ! registered_type ) { log_failure( "gen::def_typedef: failed to register type" ); - return CodeInvalid; + return InvalidCode; } CodeTypedef result = (CodeTypedef) make_code(); - result->Type = ECode::Typedef; - result->ModuleFlags = mflags; + result->Type = CT_Typedef; + result->ModuleFlags = p.mflags; result->UnderlyingType = type; if ( name.Len <= 0 ) { - if (type->Type != Untyped) + if (type->Type != CT_Untyped) { - log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_typedef: name was empty and type was not untyped (indicating its a function typedef) - %s", code_debug_str(type) ); + return InvalidCode; } result->Name = get_cached_string( type->Name ); @@ -1375,69 +1394,67 @@ CodeTypedef def_typedef( StrC name, Code type, CodeAttributes attributes, Module return result; } -CodeUnion def_union( StrC name, Code body, CodeAttributes attributes, ModuleFlag mflags ) +CodeUnion def_union( StrC name, CodeBody body, Opts_def_union p ) { null_check( def_union, body ); - if ( body->Type != ECode::Union_Body ) + if ( body->Type != CT_Union_Body ) { - log_failure( "gen::def_union: body was not a Union_Body type - %s", body.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_union: body was not a Union_Body type - %s", code_debug_str(body) ); + return InvalidCode; } - if ( attributes && attributes->Type != ECode::PlatformAttributes ) + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_union: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) ); + return InvalidCode; } CodeUnion result = (CodeUnion) make_code(); - result->ModuleFlags = mflags; - result->Type = ECode::Union; + result->ModuleFlags = p.mflags; + result->Type = CT_Union; if ( name.Ptr ) result->Name = get_cached_string( name ); result->Body = body; - if ( attributes ) - result->Attributes = attributes; + if ( p.attributes ) + result->Attributes = p.attributes; return result; } -CodeUsing def_using( StrC name, CodeType type - , CodeAttributes attributes - , ModuleFlag mflags ) +CodeUsing def_using( StrC name, CodeTypename type, Opts_def_using p ) { name_check( def_using, name ); null_check( def_using, type ); - Code register_type = def_type( name ); + CodeTypename register_type = def_type( name ); if ( ! register_type ) { log_failure( "gen::def_using: failed to register type" ); - return CodeInvalid; + return InvalidCode; } - if ( attributes && attributes->Type != ECode::PlatformAttributes ) + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_using: attributes was not a PlatformAttributes type - %s", code_debug_str(p.attributes) ); + return InvalidCode; } CodeUsing result = (CodeUsing) make_code(); result->Name = get_cached_string( name ); - result->ModuleFlags = mflags; - result->Type = ECode::Using; + result->ModuleFlags = p.mflags; + result->Type = CT_Using; result->UnderlyingType = type; - if ( attributes ) - result->Attributes = attributes; + if ( p.attributes ) + result->Attributes = p.attributes; return result; } @@ -1450,85 +1467,79 @@ CodeUsing def_using_namespace( StrC name ) result = make_code(); result->Name = get_cached_string( name ); result->Content = result->Name; - result->Type = ECode::Using_Namespace; + result->Type = CT_Using_Namespace; return (CodeUsing) result; } -CodeVar def_variable( CodeType type, StrC name, Code value - , CodeSpecifiers specifiers, CodeAttributes attributes - , ModuleFlag mflags ) +CodeVar def_variable( CodeTypename type, StrC name, Opts_def_variable p ) { name_check( def_variable, name ); null_check( def_variable, type ); - if ( attributes && attributes->Type != ECode::PlatformAttributes ) + if ( p.attributes && p.attributes->Type != CT_PlatformAttributes ) { - log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", attributes.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: attributes was not a `PlatformAttributes` type - %s", code_debug_str(p.attributes) ); + return InvalidCode; } - if ( specifiers && specifiers->Type != ECode::Specifiers ) + if ( p.specifiers && p.specifiers->Type != CT_Specifiers ) { - log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", specifiers.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: specifiers was not a `Specifiers` type - %s", code_debug_str(p.specifiers) ); + return InvalidCode; } - if ( type->Type != ECode::Typename ) + if ( type->Type != CT_Typename ) { - log_failure( "gen::def_variable: type was not a Typename - %s", type.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: type was not a Typename - %s", code_debug_str(type) ); + return InvalidCode; } - if ( value && value->Type != ECode::Untyped ) + if ( p.value && p.value->Type != CT_Untyped ) { - log_failure( "gen::def_variable: value was not a `Untyped` type - %s", value.debug_str() ); - return CodeInvalid; + log_failure( "gen::def_variable: value was not a `Untyped` type - %s", code_debug_str(p.value) ); + return InvalidCode; } CodeVar result = (CodeVar) make_code(); result->Name = get_cached_string( name ); - result->Type = ECode::Variable; - result->ModuleFlags = mflags; + result->Type = CT_Variable; + result->ModuleFlags = p.mflags; result->ValueType = type; - if ( attributes ) - result->Attributes = attributes; + if ( p.attributes ) + result->Attributes = p.attributes; - if ( specifiers ) - result->Specs = specifiers; + if ( p.specifiers ) + result->Specs = p.specifiers; - if ( value ) - result->Value = value; + if ( p.value ) + result->Value = p.value; return result; } #pragma region Helper Macros for def_**_body functions #define def_body_start( Name_ ) \ -using namespace ECode; \ - \ if ( num <= 0 ) \ { \ log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ - return CodeInvalid; \ + return InvalidCode; \ } #define def_body_code_array_start( Name_ ) \ -using namespace ECode; \ - \ if ( num <= 0 ) \ { \ log_failure("gen::" stringize(Name_) ": num cannot be zero or negative"); \ - return CodeInvalid; \ + return InvalidCode; \ } \ \ if ( codes == nullptr ) \ { \ log_failure("gen::" stringize(Name_)" : Provided a null array of codes"); \ - return CodeInvalid; \ + return InvalidCode; \ } #pragma endregion Helper Macros for def_**_body functions @@ -1538,7 +1549,7 @@ CodeBody def_class_body( s32 num, ... ) def_body_start( def_class_body ); CodeBody result = ( CodeBody )make_code(); - result->Type = Class_Body; + result->Type = CT_Class_Body; va_list va; va_start( va, num ); @@ -1552,20 +1563,20 @@ CodeBody def_class_body( s32 num, ... ) log_failure("gen::" "def_class_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_CLASS_UNALLOWED_TYPES - log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -1579,7 +1590,7 @@ CodeBody def_class_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Function_Body; + result->Type = CT_Function_Body; do { @@ -1589,20 +1600,20 @@ CodeBody def_class_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_class_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_CLASS_UNALLOWED_TYPES - log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_class_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); @@ -1615,7 +1626,7 @@ CodeBody def_enum_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Enum_Body; + result->Type = CT_Enum_Body; va_list va; va_start(va, num); @@ -1627,16 +1638,16 @@ CodeBody def_enum_body( s32 num, ... ) if ( ! entry ) { log_failure("gen::def_enum_body: Provided a null entry"); - return CodeInvalid; + return InvalidCode; } - if ( entry->Type != Untyped && entry->Type != Comment ) + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { - log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::def_enum_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) ); + return InvalidCode; } - result.append( entry ); + body_append(result, entry ); } while ( num--, num > 0 ); va_end(va); @@ -1650,7 +1661,7 @@ CodeBody def_enum_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Enum_Body; + result->Type = CT_Enum_Body; do { @@ -1659,16 +1670,16 @@ CodeBody def_enum_body( s32 num, Code* codes ) if ( ! entry ) { log_failure("gen::def_enum_body: Provided a null entry"); - return CodeInvalid; + return InvalidCode; } - if ( entry->Type != Untyped && entry->Type != Comment ) + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { - log_failure("gen::def_enum_body: Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::def_enum_body: Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; } - result.append( entry ); + body_append(result, entry ); } while ( codes++, num--, num > 0 ); @@ -1681,7 +1692,7 @@ CodeBody def_export_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Export_Body; + result->Type = CT_Export_Body; va_list va; va_start(va, num); @@ -1693,20 +1704,20 @@ CodeBody def_export_body( s32 num, ... ) if (!entry) { log_failure("gen::" "def_export_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -1720,7 +1731,7 @@ CodeBody def_export_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Export_Body; + result->Type = CT_Export_Body; do { @@ -1730,20 +1741,20 @@ CodeBody def_export_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_export_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_EXPORT_UNALLOWED_TYPES - log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_export_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); @@ -1756,32 +1767,32 @@ CodeBody def_extern_link_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Extern_Linkage_Body; + result->Type = CT_Extern_Linkage_Body; va_list va; va_start(va, num); do { - Code_POD pod = va_arg(va, Code_POD); - Code entry = pcast(Code, pod); + Code_POD pod = va_arg(va, Code_POD); + Code entry = pcast(Code, pod); if (!entry) { log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -1795,7 +1806,7 @@ CodeBody def_extern_link_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Extern_Linkage_Body; + result->Type = CT_Extern_Linkage_Body; do { @@ -1805,21 +1816,20 @@ CodeBody def_extern_link_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_extern_linkage_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_EXTERN_LINKAGE_UNALLOWED_TYPES - log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_extern_linkage_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); - + body_append(result, entry); } while (num--, num > 0); @@ -1832,7 +1842,7 @@ CodeBody def_function_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Function_Body; + result->Type = CT_Function_Body; va_list va; va_start(va, num); @@ -1844,21 +1854,21 @@ CodeBody def_function_body( s32 num, ... ) if (!entry) { log_failure("gen::" stringize(def_function_body) ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" stringize(def_function_body) ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -1872,7 +1882,7 @@ CodeBody def_function_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Function_Body; + result->Type = CT_Function_Body; do { @@ -1882,19 +1892,19 @@ CodeBody def_function_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_function_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_FUNCTION_UNALLOWED_TYPES - log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_function_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); @@ -1907,7 +1917,7 @@ CodeBody def_global_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Global_Body; + result->Type = CT_Global_Body; va_list va; va_start(va, num); @@ -1919,24 +1929,25 @@ CodeBody def_global_body( s32 num, ... ) if (!entry) { log_failure("gen::" "def_global_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { - case Global_Body: - result.append( entry.cast() ) ; + case CT_Global_Body: + // result.body_append( entry.code_cast() ) ; + body_append_body( result, cast(CodeBody, entry) ); continue; GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); - return (*Code::Invalid.ast); + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -1950,7 +1961,7 @@ CodeBody def_global_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Global_Body; + result->Type = CT_Global_Body; do { @@ -1960,24 +1971,24 @@ CodeBody def_global_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_global_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { - case Global_Body: - result.append( entry.cast() ) ; + case CT_Global_Body: + body_append_body(result, cast(CodeBody, entry) ); continue; GEN_AST_BODY_GLOBAL_UNALLOWED_TYPES - log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_global_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); @@ -1990,7 +2001,7 @@ CodeBody def_namespace_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Namespace_Body; + result->Type = CT_Namespace_Body; va_list va; va_start(va, num); @@ -2002,20 +2013,20 @@ CodeBody def_namespace_body( s32 num, ... ) if (!entry) { log_failure("gen::" "def_namespace_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -2029,7 +2040,7 @@ CodeBody def_namespace_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Global_Body; + result->Type = CT_Global_Body; do { @@ -2039,26 +2050,26 @@ CodeBody def_namespace_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_namespace_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_NAMESPACE_UNALLOWED_TYPES - log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::" "def_namespace_body" ": Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); return result; } -CodeParam def_params( s32 num, ... ) +CodeParams def_params( s32 num, ... ) { def_body_start( def_params ); @@ -2066,66 +2077,66 @@ CodeParam def_params( s32 num, ... ) va_start(va, num); Code_POD pod = va_arg(va, Code_POD); - CodeParam param = pcast( CodeParam, pod ); + CodeParams param = pcast( CodeParams, pod ); null_check( def_params, param ); - if ( param->Type != Parameters ) + if ( param->Type != CT_Parameters ) { log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); - return CodeInvalid; + return InvalidCode; } - CodeParam result = (CodeParam) param.duplicate(); + CodeParams result = (CodeParams) code_duplicate(param); while ( -- num ) { pod = va_arg(va, Code_POD); - param = pcast( CodeParam, pod ); + param = pcast( CodeParams, pod ); - if ( param->Type != Parameters ) + if ( param->Type != CT_Parameters ) { log_failure( "gen::def_params: param %d is not a Parameters", num - num + 1 ); - return CodeInvalid; + return InvalidCode; } - result.append( param ); + params_append(result, param ); } va_end(va); return result; } -CodeParam def_params( s32 num, CodeParam* codes ) +CodeParams def_params( s32 num, CodeParams* codes ) { def_body_code_array_start( def_params ); -# define check_current() \ - if ( current.ast == nullptr ) \ - { \ - log_failure("gen::def_params: Provide a null code in codes array"); \ - return CodeInvalid; \ - } \ - \ - if (current->Type != Parameters ) \ - { \ - log_failure("gen::def_params: Code in coes array is not of paramter type - %s", current.debug_str() ); \ - return CodeInvalid; \ +# define check_current(current) \ + if ( current == nullptr ) \ + { \ + log_failure("gen::def_params: Provide a null code in codes array"); \ + return InvalidCode; \ + } \ + \ + if (current->Type != CT_Parameters ) \ + { \ + log_failure("gen::def_params: Code in coes array is not of paramter type - %s", code_debug_str(current) ); \ + return InvalidCode; \ } - CodeParam current = (CodeParam) codes->duplicate(); - check_current(); + CodeParams current = (CodeParams)code_duplicate(* codes); + check_current(current); - CodeParam - result = (CodeParam) make_code(); + CodeParams + result = (CodeParams) make_code(); result->Name = current->Name; result->Type = current->Type; result->ValueType = current->ValueType; while( codes++, current = * codes, num--, num > 0 ) { - check_current(); - result.append( current ); + check_current(current); + params_append(result, current ); } # undef check_current @@ -2137,26 +2148,26 @@ CodeSpecifiers def_specifiers( s32 num, ... ) if ( num <= 0 ) { log_failure("gen::def_specifiers: num cannot be zero or less"); - return CodeInvalid; + return InvalidCode; } - if ( num > AST::ArrSpecs_Cap ) + if ( num > AST_ArrSpecs_Cap ) { log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); - return CodeInvalid; + return InvalidCode; } CodeSpecifiers result = (CodeSpecifiers) make_code(); - result->Type = ECode::Specifiers; + result->Type = CT_Specifiers; va_list va; va_start(va, num); do { - SpecifierT type = (SpecifierT)va_arg(va, int); + Specifier type = (Specifier)va_arg(va, int); - result.append( type ); + specifiers_append(result, type ); } while ( --num, num ); va_end(va); @@ -2164,28 +2175,28 @@ CodeSpecifiers def_specifiers( s32 num, ... ) return result; } -CodeSpecifiers def_specifiers( s32 num, SpecifierT* specs ) +CodeSpecifiers def_specifiers( s32 num, Specifier* specs ) { if ( num <= 0 ) { log_failure("gen::def_specifiers: num cannot be zero or less"); - return CodeInvalid; + return InvalidCode; } - if ( num > AST::ArrSpecs_Cap ) + if ( num > AST_ArrSpecs_Cap ) { log_failure("gen::def_specifiers: num of speciifers to define AST larger than AST specicifier capacity - %d", num); - return CodeInvalid; + return InvalidCode; } CodeSpecifiers result = (CodeSpecifiers) make_code(); - result->Type = ECode::Specifiers; + result->Type = CT_Specifiers; s32 idx = 0; do { - result.append( specs[idx] ); + specifiers_append(result, specs[idx] ); idx++; } while ( --num, num ); @@ -2199,7 +2210,7 @@ CodeBody def_struct_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Struct_Body; + result->Type = CT_Struct_Body; va_list va; va_start(va, num); @@ -2211,20 +2222,20 @@ CodeBody def_struct_body( s32 num, ... ) if (!entry) { log_failure("gen::" "def_struct_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str()); - return CodeInvalid; + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry)); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); va_end(va); @@ -2238,7 +2249,7 @@ CodeBody def_struct_body( s32 num, Code* codes ) CodeBody result = (CodeBody) make_code(); - result->Type = Struct_Body; + result->Type = CT_Struct_Body; do { @@ -2248,20 +2259,20 @@ CodeBody def_struct_body( s32 num, Code* codes ) if (!entry) { log_failure("gen::" "def_struct_body" ": Provided an null entry"); - return CodeInvalid; + return InvalidCode; } switch (entry->Type) { GEN_AST_BODY_STRUCT_UNALLOWED_TYPES - log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::" "def_struct_body" ": Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; default: break; } - result.append(entry); + body_append(result, entry); } while (num--, num > 0); @@ -2274,7 +2285,7 @@ CodeBody def_union_body( s32 num, ... ) CodeBody result = (CodeBody) make_code(); - result->Type = Union_Body; + result->Type = CT_Union_Body; va_list va; va_start(va, num); @@ -2286,16 +2297,16 @@ CodeBody def_union_body( s32 num, ... ) if ( ! entry ) { log_failure("gen::def_union_body: Provided a null entry"); - return CodeInvalid; + return InvalidCode; } - if ( entry->Type != Untyped && entry->Type != Comment ) + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { - log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::def_union_body: Entry type is not allowed - %s. Must be of untyped or comment type.", code_debug_str(entry) ); + return InvalidCode; } - result.append( entry ); + body_append(result, entry ); } while ( num--, num > 0 ); va_end(va); @@ -2303,13 +2314,13 @@ CodeBody def_union_body( s32 num, ... ) return result; } -CodeBody def_union_body( s32 num, CodeUnion* codes ) +CodeBody def_union_body( s32 num, Code* codes ) { def_body_code_array_start( def_union_body ); CodeBody result = (CodeBody) make_code(); - result->Type = Union_Body; + result->Type = CT_Union_Body; do { @@ -2318,16 +2329,16 @@ CodeBody def_union_body( s32 num, CodeUnion* codes ) if ( ! entry ) { log_failure("gen::def_union_body: Provided a null entry"); - return CodeInvalid; + return InvalidCode; } - if ( entry->Type != Untyped && entry->Type != Comment ) + if ( entry->Type != CT_Untyped && entry->Type != CT_Comment ) { - log_failure("gen::def_union_body: Entry type is not allowed: %s", entry.debug_str() ); - return CodeInvalid; + log_failure("gen::def_union_body: Entry type is not allowed: %s", code_debug_str(entry) ); + return InvalidCode; } - result.append( entry ); + body_append(result, entry ); } while ( codes++, num--, num > 0 ); diff --git a/base/components/lexer.cpp b/base/components/lexer.cpp new file mode 100644 index 0000000..e19f478 --- /dev/null +++ b/base/components/lexer.cpp @@ -0,0 +1,1349 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "interface.upfront.cpp" +#include "gen/etoktype.cpp" +#endif + +GEN_NS_PARSER_BEGIN + +enum TokFlags : u32 +{ + TF_Operator = bit(0), + TF_Assign = bit(1), + TF_Preprocess = bit(2), + TF_Preprocess_Cond = bit(3), + TF_Attribute = bit(6), + TF_AccessOperator = bit( 7 ), + TF_AccessSpecifier = bit( 8 ), + TF_Specifier = bit( 9 ), + TF_EndDefinition = bit( 10 ), // Either ; or } + TF_Formatting = bit( 11 ), + TF_Literal = bit( 12 ), + + TF_Null = 0, + TF_UnderlyingType = GEN_U32_MAX, +}; + +struct Token +{ + char const* Text; + sptr Length; + TokType Type; + s32 Line; + s32 Column; + u32 Flags; +}; + +constexpr Token NullToken { nullptr, 0, Tok_Invalid, false, 0, TF_Null }; + +AccessSpec tok_to_access_specifier(Token tok) +{ + return scast(AccessSpec, tok.Type); +} + +StrC tok_to_str(Token tok) +{ + StrC str = { tok.Length, tok.Text }; + return str; +} + +bool tok_is_valid( Token tok ) +{ + return tok.Text && tok.Length && tok.Type != Tok_Invalid; +} + +bool tok_is_access_operator(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_AccessOperator ); +} + +bool tok_is_access_specifier(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_AccessSpecifier ); +} + +bool tok_is_attribute(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_Attribute ); +} + +bool tok_is_operator(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_Operator ); +} + +bool tok_is_preprocessor(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_Preprocess ); +} + +bool tok_is_preprocess_cond(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_Preprocess_Cond ); +} + +bool tok_is_specifier(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_Specifier ); +} + +bool tok_is_end_definition(Token tok) +{ + return bitfield_is_equal( u32, tok.Flags, TF_EndDefinition ); +} + +String tok_to_string(Token tok) +{ + String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); + + StrC type_str = toktype_to_str( tok.Type ); + + string_append_fmt( & result, "Line: %d Column: %d, Type: %.*s Content: %.*s" + , tok.Line, tok.Column + , type_str.Len, type_str.Ptr + , tok.Length, tok.Text + ); + + return result; +} + +struct TokArray +{ + Array(Token) Arr; + s32 Idx; +}; + +bool lex__eat( TokArray* self, TokType type ); + +Token* lex_current(TokArray* self, bool skip_formatting ) +{ + if ( skip_formatting ) + { + while ( self->Arr[self->Idx].Type == Tok_NewLine || self->Arr[self->Idx].Type == Tok_Comment ) + self->Idx++; + } + + return & self->Arr[self->Idx]; +} + +Token* lex_peek(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + + if ( skip_formatting ) + { + while ( self.Arr[idx].Type == Tok_NewLine ) + idx++; + + return & self.Arr[idx]; + } + + return & self.Arr[idx]; +} + +Token* lex_previous(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + + if ( skip_formatting ) + { + while ( self.Arr[idx].Type == Tok_NewLine ) + idx --; + + return & self.Arr[idx]; + } + + return & self.Arr[idx - 1]; +} + +Token* lex_next(TokArray self, bool skip_formatting) +{ + s32 idx = self.Idx; + + if ( skip_formatting ) + { + while ( self.Arr[idx].Type == Tok_NewLine ) + idx++; + + return & self.Arr[idx + 1]; + } + + return & self.Arr[idx + 1]; +} + +global FixedArena_256KB Lexer_defines_map_arena; +global StringTable Lexer_defines; +global Array(Token) Lexer_Tokens; + +#define current ( * ctx->scanner ) + +#define move_forward() \ + { \ + if ( current == '\n' ) \ + { \ + ctx->line++; \ + ctx->column = 1; \ + } \ + else \ + { \ + ctx->column++; \ + } \ + ctx->left--; \ + ctx->scanner++; \ + } + +#define skip_whitespace() \ + while ( ctx->left && char_is_space( current ) ) \ + { \ + move_forward(); \ + } + +#define end_line() \ + do \ + { \ + while ( ctx->left && current == ' ' ) \ + { \ + move_forward(); \ + } \ + if ( ctx->left && current == '\r' ) \ + { \ + move_forward(); \ + move_forward(); \ + } \ + else if ( ctx->left && current == '\n' ) \ + { \ + move_forward(); \ + } \ + } \ + while (0) + +enum +{ + Lex_Continue, + Lex_ReturnNull, +}; + +struct LexContext +{ + StrC content; + s32 left; + char const* scanner; + s32 line; + s32 column; + StringTable defines; + Token token; +}; + +forceinline +s32 lex_preprocessor_directive( LexContext* ctx ) +{ + char const* hash = ctx->scanner; + Token hash_tok = { hash, 1, Tok_Preprocess_Hash, ctx->line, ctx->column, TF_Preprocess }; + array_append( Lexer_Tokens, hash_tok ); + + move_forward(); + skip_whitespace(); + + ctx->token.Text = ctx->scanner; + while (ctx->left && ! char_is_space(current) ) + { + move_forward(); + ctx->token.Length++; + } + + ctx->token.Type = strc_to_toktype( tok_to_str(ctx->token) ); + + bool is_preprocessor = ctx->token.Type >= Tok_Preprocess_Define && ctx->token.Type <= Tok_Preprocess_Pragma; + if ( ! is_preprocessor ) + { + ctx->token.Type = Tok_Preprocess_Unsupported; + + // Its an unsupported directive, skip it + s32 within_string = false; + s32 within_char = false; + while ( ctx->left ) + { + if ( current == '"' && ! within_char ) + within_string ^= true; + + if ( current == '\'' && ! within_string ) + within_char ^= true; + + if ( current == '\\' && ! within_string && ! within_char ) + { + move_forward(); + ctx->token.Length++; + + if ( current == '\r' ) + { + move_forward(); + ctx->token.Length++; + } + + if ( current == '\n' ) + { + move_forward(); + ctx->token.Length++; + continue; + } + else + { + log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" + " in preprocessor directive (%d, %d)\n%.100s" + , current, ctx->line, ctx->column + , ctx->token.Line, ctx->token.Column, ctx->token.Text ); + break; + } + } + + if ( current == '\r' ) + { + move_forward(); + ctx->token.Length++; + } + + if ( current == '\n' ) + { + move_forward(); + ctx->token.Length++; + break; + } + + move_forward(); + ctx->token.Length++; + } + + ctx->token.Length = ctx->token.Length + ctx->token.Text - hash; + ctx->token.Text = hash; + array_append( Lexer_Tokens, ctx->token ); + return Lex_Continue; // Skip found token, its all handled here. + } + + if ( ctx->token.Type == Tok_Preprocess_Else || ctx->token.Type == Tok_Preprocess_EndIf ) + { + ctx->token.Flags |= TF_Preprocess_Cond; + array_append( Lexer_Tokens, ctx->token ); + end_line(); + return Lex_Continue; + } + else if ( ctx->token.Type >= Tok_Preprocess_If && ctx->token.Type <= Tok_Preprocess_ElIf ) + { + ctx->token.Flags |= TF_Preprocess_Cond; + } + + array_append( Lexer_Tokens, ctx->token ); + + skip_whitespace(); + + if ( ctx->token.Type == Tok_Preprocess_Define ) + { + Token name = { ctx->scanner, 0, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess }; + + name.Text = ctx->scanner; + name.Length = 1; + move_forward(); + + while ( ctx->left && ( char_is_alphanumeric(current) || current == '_' ) ) + { + move_forward(); + name.Length++; + } + + if ( ctx->left && current == '(' ) + { + move_forward(); + name.Length++; + } + + array_append( Lexer_Tokens, name ); + + u64 key = crc32( name.Text, name.Length ); + hashtable_set(ctx->defines, key, tok_to_str(name) ); + } + + Token preprocess_content = { ctx->scanner, 0, Tok_Preprocess_Content, ctx->line, ctx->column, TF_Preprocess }; + + if ( ctx->token.Type == Tok_Preprocess_Include ) + { + preprocess_content.Type = Tok_String; + + if ( current != '"' && current != '<' ) + { + String directive_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 80, ctx->left + preprocess_content.Length ), ctx->token.Text ); + + log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s" + , current + , preprocess_content.Line + , preprocess_content.Column + , (char*) directive_str + ); + return Lex_ReturnNull; + } + move_forward(); + preprocess_content.Length++; + + while ( ctx->left && current != '"' && current != '>' ) + { + move_forward(); + preprocess_content.Length++; + } + + move_forward(); + preprocess_content.Length++; + + if ( current == '\r' && ctx->scanner[1] == '\n' ) + { + move_forward(); + move_forward(); + } + else if ( current == '\n' ) + { + move_forward(); + } + + array_append( Lexer_Tokens, preprocess_content ); + return Lex_Continue; // Skip found token, its all handled here. + } + + s32 within_string = false; + s32 within_char = false; + + // SkipWhitespace(); + while ( ctx->left ) + { + if ( current == '"' && ! within_char ) + within_string ^= true; + + if ( current == '\'' && ! within_string ) + within_char ^= true; + + if ( current == '\\' && ! within_string && ! within_char ) + { + move_forward(); + preprocess_content.Length++; + + if ( current == '\r' ) + { + move_forward(); + preprocess_content.Length++; + } + + if ( current == '\n' ) + { + move_forward(); + preprocess_content.Length++; + continue; + } + else + { + String directive_str = string_make_length( GlobalAllocator, ctx->token.Text, ctx->token.Length ); + String content_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 400, ctx->left + preprocess_content.Length ), preprocess_content.Text ); + + log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)" + " in preprocessor directive '%s' (%d, %d)\n%s" + , current, ctx->line, ctx->column + , directive_str, preprocess_content.Line, preprocess_content.Column + , content_str ); + break; + } + } + + if ( current == '\r' ) + { + break; + //move_forward(); + } + + if ( current == '\n' ) + { + //move_forward(); + break; + } + + move_forward(); + preprocess_content.Length++; + } + + array_append( Lexer_Tokens, preprocess_content ); + return Lex_Continue; // Skip found token, its all handled here. +} + +forceinline +void lex_found_token( LexContext* ctx ) +{ + if ( ctx->token.Type != Tok_Invalid ) + { + array_append( Lexer_Tokens, ctx->token ); + return; + } + + TokType type = strc_to_toktype( tok_to_str(ctx->token) ); + + if (type <= Tok_Access_Public && type >= Tok_Access_Private ) + { + ctx->token.Flags |= TF_AccessSpecifier; + } + + if ( type > Tok___Attributes_Start ) + { + ctx->token.Flags |= TF_Attribute; + } + + if ( type == Tok_Decl_Extern_Linkage ) + { + skip_whitespace(); + + if ( current != '"' ) + { + type = Tok_Spec_Extern; + ctx->token.Flags |= TF_Specifier; + } + + ctx->token.Type = type; + array_append( Lexer_Tokens, ctx->token ); + return; + } + + if ( ( type <= Tok_Star && type >= Tok_Spec_Alignas) + || type == Tok_Ampersand + || type == Tok_Ampersand_DBL ) + { + ctx->token.Type = type; + ctx->token.Flags |= TF_Specifier; + array_append( Lexer_Tokens, ctx->token ); + return; + } + + + if ( type != Tok_Invalid ) + { + ctx->token.Type = type; + array_append( Lexer_Tokens, ctx->token ); + return; + } + + u64 key = 0; + if ( current == '(') + key = crc32( ctx->token.Text, ctx->token.Length + 1 ); + else + key = crc32( ctx->token.Text, ctx->token.Length ); + + StrC* define = hashtable_get(ctx->defines, key ); + if ( define ) + { + ctx->token.Type = Tok_Preprocess_Macro; + + // Want to ignore any arguments the define may have as they can be execution expressions. + if ( ctx->left && current == '(' ) + { + move_forward(); + ctx->token.Length++; + + s32 level = 0; + while ( ctx->left && (current != ')' || level > 0) ) + { + if ( current == '(' ) + level++; + + else if ( current == ')' && level > 0 ) + level--; + + move_forward(); + ctx->token.Length++; + } + + move_forward(); + ctx->token.Length++; + } + + //if ( current == '\r' && ctx->scanner[1] == '\n' ) + //{ + // move_forward(); + // ctx->token.Length++; + //} + //else if ( current == '\n' ) + //{ + // move_forward(); + // ctx->token.Length++; + //} + } + else + { + ctx->token.Type = Tok_Identifier; + } + + array_append( Lexer_Tokens, ctx->token ); +} + +neverinline +// TokArray lex( Array tokens, StrC content ) +TokArray lex( StrC content ) +{ + LexContext c; LexContext* ctx = & c; + c.content = content; + c.left = content.Len; + c.scanner = content.Ptr; + c.defines = Lexer_defines; + + char const* word = c.scanner; + s32 word_length = 0; + + c.line = 1; + c.column = 1; + + skip_whitespace(); + if ( c.left <= 0 ) + { + log_failure( "gen::lex: no tokens found (only whitespace provided)" ); + TokArray null_array = {}; + return null_array; + } + + for ( StringCached* entry = array_begin(PreprocessorDefines); entry != array_end(PreprocessorDefines); entry = array_next(PreprocessorDefines, entry)) + { + s32 length = 0; + char const* entry_scanner = (*entry).Ptr; + while ( entry->Len > length && (char_is_alphanumeric( *entry_scanner ) || *entry_scanner == '_') ) + { + entry_scanner++; + length ++; + } + if ( entry_scanner[0] == '(' ) + { + length++; + } + + u64 key = crc32( entry->Ptr, length ); + hashtable_set(c.defines, key, * entry ); + } + + array_clear(Lexer_Tokens); + + while (c.left ) + { + #if 0 + if (Tokens.num()) + { + log_fmt("\nLastTok: %S", Tokens.back().to_string()); + } + #endif + + { + Token thanks_c = { c.scanner, 0, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + } + + bool is_define = false; + + if ( c.column == 1 ) + { + if ( current == '\r') + { + move_forward(); + c.token.Length = 1; + } + + if ( current == '\n' ) + { + move_forward(); + + c.token.Type = Tok_NewLine; + c.token.Length++; + + array_append( Lexer_Tokens, c.token ); + continue; + } + } + + c.token.Length = 0; + + skip_whitespace(); + if ( c.left <= 0 ) + break; + + switch ( current ) + { + if (array_back(Lexer_Tokens)->Length > 100 ) { + __debugbreak(); + } + + case '#': + { + s32 result = lex_preprocessor_directive( ctx ); + switch ( result ) + { + case Lex_Continue: + { + //TokType last_type = Tokens[array_get_header(Tokens)->Num - 2].Type; + //if ( last_type == Tok_Preprocess_Pragma ) + { + { + Token thanks_c = { c.scanner, 0, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + } + if ( current == '\r') + { + move_forward(); + c.token.Length = 1; + } + + if ( current == '\n' ) + { + c.token.Type = Tok_NewLine; + c.token.Length++; + move_forward(); + + array_append( Lexer_Tokens, c.token ); + } + } + + continue; + } + + case Lex_ReturnNull: + { + TokArray tok_array = {}; + return tok_array; + } + } + } + case '.': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Access_MemberSymbol; + c.token.Flags = TF_AccessOperator; + + if (c.left) { + move_forward(); + } + + if ( current == '.' ) + { + move_forward(); + if( current == '.' ) + { + c.token.Length = 3; + c.token.Type = Tok_Varadic_Argument; + c.token.Flags = TF_Null; + move_forward(); + } + else + { + String context_str = string_fmt_buf( GlobalAllocator, "%s", c.scanner, min( 100, c.left ) ); + + log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", current, c.line, c.column, context_str ); + } + } + + goto FoundToken; + } + case '&' : + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Ampersand; + c.token.Flags |= TF_Operator; + c.token.Flags |= TF_Specifier; + + if (c.left) + move_forward(); + + if ( current == '&' ) // && + { + c.token.Length = 2; + c.token.Type = Tok_Ampersand_DBL; + + if (c.left) + move_forward(); + } + + goto FoundToken; + } + case ':': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Assign_Classifer; + // Can be either a classifier (ParentType, Bitfield width), or ternary else + // token.Type = Tok_Colon; + + if (c.left) + move_forward(); + + if ( current == ':' ) + { + move_forward(); + c.token.Type = Tok_Access_StaticSymbol; + c.token.Length++; + } + goto FoundToken; + } + case '{': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_BraceCurly_Open; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '}': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_BraceCurly_Close; + c.token.Flags = TF_EndDefinition; + + if (c.left) + move_forward(); + + end_line(); + goto FoundToken; + } + case '[': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_BraceSquare_Open; + if ( c.left ) + { + move_forward(); + + if ( current == ']' ) + { + c.token.Length = 2; + c.token.Type = Tok_Operator; + move_forward(); + } + } + goto FoundToken; + } + case ']': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_BraceSquare_Close; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '(': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Capture_Start; + + if (c.left) + move_forward(); + goto FoundToken; + } + case ')': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Capture_End; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '\'': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Char; + c.token.Flags = TF_Literal; + + move_forward(); + + if ( c.left && current == '\\' ) + { + move_forward(); + c.token.Length++; + + if ( current == '\'' ) + { + move_forward(); + c.token.Length++; + } + } + + while ( c.left && current != '\'' ) + { + move_forward(); + c.token.Length++; + } + + if ( c.left ) + { + move_forward(); + c.token.Length++; + } + goto FoundToken; + } + case ',': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Comma; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + goto FoundToken; + } + case '*': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Star; + c.token.Flags |= TF_Specifier; + c.token.Flags |= TF_Operator; + + if (c.left) + move_forward(); + + if ( current == '=' ) + { + c.token.Length++; + c.token.Flags |= TF_Assign; + // c.token.Type = Tok_Assign_Multiply; + + if ( c.left ) + move_forward(); + } + + goto FoundToken; + } + case ';': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Statement_End; + c.token.Flags = TF_EndDefinition; + + if (c.left) + move_forward(); + + end_line(); + goto FoundToken; + } + case '"': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_String; + c.token.Flags |= TF_Literal; + + move_forward(); + while ( c.left ) + { + if ( current == '"' ) + { + move_forward(); + break; + } + + if ( current == '\\' ) + { + move_forward(); + c.token.Length++; + + if ( c.left ) + { + move_forward(); + c.token.Length++; + } + continue; + } + + move_forward(); + c.token.Length++; + } + goto FoundToken; + } + case '?': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Operator; + // c.token.Type = Tok_Ternary; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + + goto FoundToken; + } + case '=': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Operator; + // c.token.Type = Tok_Assign; + c.token.Flags = TF_Operator; + c.token.Flags |= TF_Assign; + + if (c.left) + move_forward(); + + if ( current == '=' ) + { + c.token.Length++; + c.token.Flags = TF_Operator; + + if (c.left) + move_forward(); + } + + goto FoundToken; + } + case '+': + { + // c.token.Type = Tok_Add + + } + case '%': + { + // c.token.Type = Tok_Modulo; + + } + case '^': + { + // c.token.Type = Tok_B_XOr; + } + case '~': + { + // c.token.Type = Tok_Unary_Not; + + } + case '!': + { + // c.token.Type = Tok_L_Not; + } + case '<': + { + // c.token.Type = Tok_Lesser; + + } + case '>': + { + // c.token.Type = Tok_Greater; + + } + case '|': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Operator; + c.token.Flags = TF_Operator; + // token.Type = Tok_L_Or; + + if (c.left) + move_forward(); + + if ( current == '=' ) + { + c.token.Length++; + c.token.Flags |= TF_Assign; + // token.Flags |= TokFlags::Assignment; + // token.Type = Tok_Assign_L_Or; + + if (c.left) + move_forward(); + } + else while ( c.left && current == *(c.scanner - 1) && c.token.Length < 3 ) + { + c.token.Length++; + + if (c.left) + move_forward(); + } + goto FoundToken; + } + + // Dash is unfortunatlly a bit more complicated... + case '-': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Operator; + // token.Type = Tok_Subtract; + c.token.Flags = TF_Operator; + if ( c.left ) + { + move_forward(); + + if ( current == '>' ) + { + c.token.Length++; +// token.Type = Tok_Access_PointerToMemberSymbol; + c.token.Flags |= TF_AccessOperator; + move_forward(); + + if ( current == '*' ) + { +// token.Type = Tok_Access_PointerToMemberOfPointerSymbol; + c.token.Length++; + move_forward(); + } + } + else if ( current == '=' ) + { + c.token.Length++; + // token.Type = Tok_Assign_Subtract; + c.token.Flags |= TF_Assign; + + if (c.left) + move_forward(); + } + else while ( c.left && current == *(c.scanner - 1) && c.token.Length < 3 ) + { + c.token.Length++; + + if (c.left) + move_forward(); + } + } + goto FoundToken; + } + case '/': + { + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Operator; + // token.Type = Tok_Divide; + c.token.Flags = TF_Operator; + move_forward(); + + if ( c.left ) + { + if ( current == '=' ) + { + // token.Type = TokeType::Assign_Divide; + move_forward(); + c.token.Length++; + c.token.Flags = TF_Assign; + } + else if ( current == '/' ) + { + c.token.Type = Tok_Comment; + c.token.Length = 2; + c.token.Flags = TF_Null; + move_forward(); + + while ( c.left && current != '\n' && current != '\r' ) + { + move_forward(); + c.token.Length++; + } + + if ( current == '\r' ) + { + move_forward(); + c.token.Length++; + } + if ( current == '\n' ) + { + move_forward(); + c.token.Length++; + } + array_append( Lexer_Tokens, c.token ); + continue; + } + else if ( current == '*' ) + { + c.token.Type = Tok_Comment; + c.token.Length = 2; + c.token.Flags = TF_Null; + move_forward(); + + bool star = current == '*'; + bool slash = c.scanner[1] == '/'; + bool at_end = star && slash; + while ( c.left && ! at_end ) + { + move_forward(); + c.token.Length++; + + star = current == '*'; + slash = c.scanner[1] == '/'; + at_end = star && slash; + } + c.token.Length += 2; + move_forward(); + move_forward(); + + if ( current == '\r' ) + { + move_forward(); + c.token.Length++; + } + if ( current == '\n' ) + { + move_forward(); + c.token.Length++; + } + array_append( Lexer_Tokens, c.token ); + // end_line(); + continue; + } + } + goto FoundToken; + } + } + + if ( char_is_alpha( current ) || current == '_' ) + { + c.token.Text = c.scanner; + c.token.Length = 1; + move_forward(); + + while ( c.left && ( char_is_alphanumeric(current) || current == '_' ) ) + { + move_forward(); + c.token.Length++; + } + + goto FoundToken; + } + else if ( char_is_digit(current) ) + { + // This is a very brute force lex, no checks are done for validity of literal. + + c.token.Text = c.scanner; + c.token.Length = 1; + c.token.Type = Tok_Number; + c.token.Flags = TF_Literal; + move_forward(); + + if (c.left + && ( current == 'x' || current == 'X' + || current == 'b' || current == 'B' + || current == 'o' || current == 'O' ) + ) + { + move_forward(); + c.token.Length++; + + while ( c.left && char_is_hex_digit(current) ) + { + move_forward(); + c.token.Length++; + } + + goto FoundToken; + } + + while ( c.left && char_is_digit(current) ) + { + move_forward(); + c.token.Length++; + } + + if ( c.left && current == '.' ) + { + move_forward(); + c.token.Length++; + + while ( c.left && char_is_digit(current) ) + { + move_forward(); + c.token.Length++; + } + + // Handle number literal suffixes in a botched way + if (c.left && ( + current == 'l' || current == 'L' || // long/long long + current == 'u' || current == 'U' || // unsigned + current == 'f' || current == 'F' || // float + current == 'i' || current == 'I' || // imaginary + current == 'z' || current == 'Z')) // complex + { + char prev = current; + move_forward(); + c.token.Length++; + + // Handle 'll'/'LL' as a special case when we just processed an 'l'/'L' + if (c.left && (prev == 'l' || prev == 'L') && (current == 'l' || current == 'L')) + { + move_forward(); + c.token.Length++; + } + } + } + + goto FoundToken; + } + else + { + s32 start = max( 0, array_num(Lexer_Tokens) - 100 ); + log_fmt("\n%d\n", start); + for ( s32 idx = start; idx < array_num(Lexer_Tokens); idx++ ) + { + log_fmt( "Token %d Type: %s : %.*s\n" + , idx + , toktype_to_str( Lexer_Tokens[ idx ].Type ).Ptr + , Lexer_Tokens[ idx ].Length, Lexer_Tokens[ idx ].Text + ); + } + + String context_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 100, c.left ), c.scanner ); + log_failure( "Failed to lex token '%c' (%d, %d)\n%s", current, c.line, c.column, context_str ); + + // Skip to next whitespace since we can't know if anything else is valid until then. + while ( c.left && ! char_is_space( current ) ) + { + move_forward(); + } + } + + FoundToken: + { + lex_found_token( ctx ); + TokType last_type = array_back(Lexer_Tokens)->Type; + if ( last_type == Tok_Preprocess_Macro ) + { + Token thanks_c = { c.scanner, 0, Tok_Invalid, c.line, c.column, TF_Null }; + c.token = thanks_c; + if ( current == '\r') + { + move_forward(); + c.token.Length = 1; + } + + if ( current == '\n' ) + { + c.token.Type = Tok_NewLine; + c.token.Length++; + move_forward(); + + array_append( Lexer_Tokens, c.token ); + continue; + } + } + } + } + + if ( array_num(Lexer_Tokens) == 0 ) + { + log_failure( "Failed to lex any tokens" ); + { + TokArray tok_array = {}; + return tok_array; + } + } + + hashtable_clear(Lexer_defines); + // defines_map_arena.free(); + TokArray result = { Lexer_Tokens, 0 }; + return result; +} +#undef current +#undef move_forward +#undef SkipWhitespace + +GEN_NS_PARSER_END diff --git a/base/components/parser.cpp b/base/components/parser.cpp new file mode 100644 index 0000000..c93aafc --- /dev/null +++ b/base/components/parser.cpp @@ -0,0 +1,5594 @@ +#ifdef GEN_INTELLISENSE_DIRECTIVES +#pragma once +#include "gen/etoktype.cpp" +#include "interface.upfront.cpp" +#include "lexer.cpp" +#endif + +GEN_NS_PARSER_BEGIN + +// TODO(Ed) : Rename ETok_Capture_Start, ETok_Capture_End to Open_Parenthesis adn Close_Parenthesis + +constexpr bool lex_dont_skip_formatting = false; +constexpr bool lex_skip_formatting = true; + +struct StackNode +{ + StackNode* Prev; + + Token Start; + Token Name; // The name of the AST node (if parsed) + StrC ProcName; // The name of the procedure +}; + +struct ParseContext +{ + TokArray Tokens; + StackNode* Scope; +}; + +void parser_push( ParseContext* ctx, StackNode* node ) +{ + node->Prev = ctx->Scope; + ctx->Scope = node; + +#if 0 && Build_Debug + log_fmt("\tEntering Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); +#endif +} + +void parser_pop(ParseContext* ctx) +{ +#if 0 && Build_Debug + log_fmt("\tPopping Context: %.*s\n", Scope->ProcName.Len, Scope->ProcName.Ptr ); +#endif + ctx->Scope = ctx->Scope->Prev; +} + +String parser_to_string(ParseContext ctx) +{ + String result = string_make_reserve( GlobalAllocator, kilobytes(4) ); + + Token scope_start = ctx.Scope->Start; + Token last_valid = ctx.Tokens.Idx >= array_num(ctx.Tokens.Arr) ? ctx.Tokens.Arr[array_num(ctx.Tokens.Arr) -1] : (* lex_current(& ctx.Tokens, true)); + + sptr length = scope_start.Length; + char const* current = scope_start.Text + length; + while ( current <= array_back( ctx.Tokens.Arr)->Text && *current != '\n' && length < 74 ) + { + current++; + length++; + } + + StrC scope_strc = { length, scope_start.Text }; + String line = string_make_strc( GlobalAllocator, scope_strc ); + string_append_fmt( & result, "\tScope : %s\n", line ); + string_free(& line); + + sptr dist = (sptr)last_valid.Text - (sptr)scope_start.Text + 2; + sptr length_from_err = dist; + + StrC err_strc = { length_from_err, last_valid.Text }; + String line_from_err = string_make_strc( GlobalAllocator, err_strc ); + + if ( length_from_err < 100 ) + string_append_fmt(& result, "\t(%d, %d):%*c\n", last_valid.Line, last_valid.Column, length_from_err, '^' ); + else + string_append_fmt(& result, "\t(%d, %d)\n", last_valid.Line, last_valid.Column ); + + StackNode* curr_scope = ctx.Scope; + s32 level = 0; + do + { + if ( tok_is_valid(curr_scope->Name) ) + { + string_append_fmt(& result, "\t%d: %s, AST Name: %.*s\n", level, curr_scope->ProcName.Ptr, curr_scope->Name.Length, curr_scope->Name.Text ); + } + else + { + string_append_fmt(& result, "\t%d: %s\n", level, curr_scope->ProcName.Ptr ); + } + + curr_scope = curr_scope->Prev; + level++; + } + while ( curr_scope ); + return result; +} + +global ParseContext Context; + +bool lex__eat(TokArray* self, TokType type ) +{ + if ( array_num(self->Arr) - self->Idx <= 0 ) + { + log_failure( "No tokens left.\n%s", parser_to_string(Context) ); + return false; + } + + Token at_idx = self->Arr[ self->Idx ]; + + if ( ( at_idx.Type == Tok_NewLine && type != Tok_NewLine ) + || ( at_idx.Type == Tok_Comment && type != Tok_Comment ) ) + { + self->Idx ++; + } + + if ( at_idx.Type != type ) + { + Token tok = * lex_current( self, lex_skip_formatting ); + log_failure( "Parse Error, TokArray::eat, Expected: ' %s ' not ' %.*s ' (%d, %d)`\n%s" + , toktype_to_str(type).Ptr + , at_idx.Length, at_idx.Text + , tok.Line + , tok.Column + , parser_to_string(Context) + ); + + return false; + } + +#if 0 && Build_Debug + log_fmt("Ate: %S\n", self->Arr[Idx].to_string() ); +#endif + + self->Idx ++; + return true; +} + +internal +void parser_init() +{ + Lexer_Tokens = array_init_reserve(Token, arena_allocator_info( & LexArena) + , ( LexAllocator_Size - sizeof( ArrayHeader ) ) / sizeof(Token) + ); + + fixed_arena_init(& Lexer_defines_map_arena); + Lexer_defines = hashtable_init_reserve(StrC, fixed_arena_allocator_info( & Lexer_defines_map_arena), 256 ); +} + +internal +void parser_deinit() +{ + Array(Token) null_array = { nullptr }; + Lexer_Tokens = null_array; +} + +#pragma region Helper Macros + +#define check_parse_args( def ) _check_parse_args(def, stringize(_func_) ) +bool _check_parse_args( StrC def, char const* func_name ) +{ + if ( def.Len <= 0 ) + { + log_failure( str_fmt_buf("gen::%s: length must greater than 0", func_name) ); + parser_pop(& Context); + return false; + } + if ( def.Ptr == nullptr ) + { + log_failure( str_fmt_buf("gen::%s: def was null", func_name) ); + parser_pop(& Context); + return false; + } + return true; +} + +# define currtok_noskip (* lex_current( & Context.Tokens, lex_dont_skip_formatting )) +# define currtok (* lex_current( & Context.Tokens, lex_skip_formatting )) +# define peektok (* lex_peek(Context.Tokens, lex_skip_formatting)) +# define prevtok (* lex_previous( Context.Tokens, lex_dont_skip_formatting)) +# define nexttok (* lex_next( Context.Tokens, lex_skip_formatting )) +# define nexttok_noskip (* lex_next( Context.Tokens, lex_dont_skip_formatting)) +# define eat( Type_ ) lex__eat( & Context.Tokens, Type_ ) +# define left ( array_num(Context.Tokens.Arr) - Context.Tokens.Idx ) + +#if GEN_COMPILER_CPP +# define def_assign( ... ) { __VA_ARGS__ } +#else +# define def_assign( ... ) __VA_ARGS__ +#endif + + +#ifdef check +#define CHECK_WAS_DEFINED +#pragma push_macro("check") +#undef check +#endif + +# define check_noskip( Type_ ) ( left && currtok_noskip.Type == Type_ ) +# define check( Type_ ) ( left && currtok.Type == Type_ ) + +# define push_scope() \ + GEN_NS_PARSER StackNode scope = { nullptr, currtok_noskip, GEN_NS_PARSER NullToken, txt( __func__ ) }; \ + parser_push( & GEN_NS_PARSER Context, & scope ) + +#pragma endregion Helper Macros + +// Procedure Forwards ( Entire parser internal parser interface ) + +internal Code parse_array_decl (); +internal CodeAttributes parse_attributes (); +internal CodeComment parse_comment (); +internal Code parse_complicated_definition ( TokType which ); +internal CodeBody parse_class_struct_body ( TokType which, Token name ); +internal Code parse_class_struct ( TokType which, bool inplace_def ); +internal CodeDefine parse_define (); +internal Code parse_expression (); +internal Code parse_forward_or_definition ( TokType which, bool is_inplace ); +internal CodeFn parse_function_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type, Token name ); +internal Code parse_function_body (); +internal CodeBody parse_global_nspace ( CodeType which ); +internal Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ); +internal Token parse_identifier ( bool* possible_member_function ); +internal CodeInclude parse_include (); +internal CodeOperator parse_operator_after_ret_type ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename ret_type ); +internal Code parse_operator_function_or_variable( bool expects_function, CodeAttributes attributes, CodeSpecifiers specifiers ); +internal CodePragma parse_pragma (); +internal CodeParams parse_params ( bool use_template_capture ); +internal CodePreprocessCond parse_preprocess_cond (); +internal Code parse_simple_preprocess ( TokType which, bool dont_consume_braces ); +internal Code parse_static_assert (); +internal void parse_template_args ( Token* token ); +internal CodeVar parse_variable_after_name ( ModuleFlag mflags, CodeAttributes attributes, CodeSpecifiers specifiers, CodeTypename type, StrC name ); +internal CodeVar parse_variable_declaration_list (); + +internal CodeClass parser_parse_class ( bool inplace_def ); +internal CodeConstructor parser_parse_constructor ( CodeSpecifiers specifiers ); +internal CodeDestructor parser_parse_destructor ( CodeSpecifiers specifiers ); +internal CodeEnum parser_parse_enum ( bool inplace_def ); +internal CodeBody parser_parse_export_body (); +internal CodeBody parser_parse_extern_link_body(); +internal CodeExtern parser_parse_extern_link (); +internal CodeFriend parser_parse_friend (); +internal CodeFn parser_parse_function (); +internal CodeNS parser_parse_namespace (); +internal CodeOpCast parser_parse_operator_cast ( CodeSpecifiers specifiers ); +internal CodeStruct parser_parse_struct ( bool inplace_def ); +internal CodeVar parser_parse_variable (); +internal CodeTemplate parser_parse_template (); +internal CodeTypename parser_parse_type ( bool from_template, bool* is_function ); +internal CodeTypedef parser_parse_typedef (); +internal CodeUnion parser_parse_union ( bool inplace_def ); +internal CodeUsing parser_parse_using (); + +constexpr bool parser_inplace_def = true; +constexpr bool parser_not_inplace_def = false; +constexpr bool parser_dont_consume_braces = true; +constexpr bool parser_consume_braces = false; +constexpr bool parser_not_from_template = false; + +constexpr bool parser_use_parenthesis = false; + +// Internal parsing functions + +constexpr bool parser_strip_formatting_dont_preserve_newlines = false; +/* + This function was an attempt at stripping formatting from any c++ code. + It has edge case failures that prevent it from being used in function bodies. +*/ +internal +String parser_strip_formatting( StrC raw_text, bool preserve_newlines ) +{ + String content = string_make_reserve( GlobalAllocator, raw_text.Len ); + + if ( raw_text.Len == 0 ) + return content; + +#define cut_length ( scanner - raw_text.Ptr - last_cut ) +#define cut_ptr ( raw_text.Ptr + last_cut ) +#define pos ( rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ) ) +#define move_fwd() do { scanner++; tokleft--; } while(0) + + s32 tokleft = raw_text.Len; + sptr last_cut = 0; + char const* scanner = raw_text.Ptr; + + if ( scanner[0] == ' ' ) + { + move_fwd(); + last_cut = 1; + } + + bool within_string = false; + bool within_char = false; + bool must_keep_newline = false; + while ( tokleft ) + { + // Skip over the content of string literals + if ( scanner[0] == '"' ) + { + move_fwd(); + + while ( tokleft && ( scanner[0] != '"' || *( scanner - 1 ) == '\\' ) ) + { + if ( scanner[0] == '\\' && tokleft > 1 ) + { + scanner += 2; + tokleft -= 2; + } + else + { + move_fwd(); + } + } + + // Skip the closing " + if ( tokleft ) + move_fwd(); + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast(sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Skip over the content of character literals + if ( scanner[0] == '\'' ) + { + move_fwd(); + + while ( tokleft + && ( scanner[0] != '\'' + || ( *(scanner -1 ) == '\\' ) + ) ) + { + move_fwd(); + } + + // Skip the closing ' + if ( tokleft ) + move_fwd(); + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Block comments + if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '*' ) + { + while ( tokleft > 1 && !(scanner[0] == '*' && scanner[1] == '/') ) + move_fwd(); + + scanner += 2; + tokleft -= 2; + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Line comments + if ( tokleft > 1 && scanner[0] == '/' && scanner[1] == '/' ) + { + must_keep_newline = true; + + scanner += 2; + tokleft -= 2; + + while ( tokleft && scanner[ 0 ] != '\n' ) + move_fwd(); + + if (tokleft) + move_fwd(); + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Tabs + if (scanner[0] == '\t') + { + if (pos > last_cut) + string_append_c_str_len( & content, cut_ptr, cut_length); + + if ( * string_back( content ) != ' ' ) + string_append_char( & content, ' ' ); + + move_fwd(); + last_cut = rcast( sptr, scanner) - rcast( sptr, raw_text.Ptr); + continue; + } + + if ( tokleft > 1 && scanner[0] == '\r' && scanner[1] == '\n' ) + { + if ( must_keep_newline || preserve_newlines ) + { + must_keep_newline = false; + + scanner += 2; + tokleft -= 2; + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + if ( pos > last_cut ) + string_append_c_str_len( & content, cut_ptr, cut_length ); + + // Replace with a space + if ( * string_back( content ) != ' ' ) + string_append_char( & content, ' ' ); + + scanner += 2; + tokleft -= 2; + + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + if ( scanner[0] == '\n' ) + { + if ( must_keep_newline || preserve_newlines ) + { + must_keep_newline = false; + + move_fwd(); + + string_append_c_str_len( & content, cut_ptr, cut_length ); + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + if ( pos > last_cut ) + string_append_c_str_len( & content, cut_ptr, cut_length ); + + // Replace with a space + if ( * string_back( content ) != ' ' ) + string_append_char( & content, ' ' ); + + move_fwd(); + + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Escaped newlines + if ( scanner[0] == '\\' ) + { + string_append_c_str_len( & content, cut_ptr, cut_length ); + + s32 amount_to_skip = 1; + if ( tokleft > 1 && scanner[1] == '\n' ) + { + amount_to_skip = 2; + } + else if ( tokleft > 2 && scanner[1] == '\r' && scanner[2] == '\n' ) + { + amount_to_skip = 3; + } + + if ( amount_to_skip > 1 && pos == last_cut ) + { + scanner += amount_to_skip; + tokleft -= amount_to_skip; + } + else + move_fwd(); + + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + continue; + } + + // Consectuive spaces + if ( tokleft > 1 && char_is_space( scanner[0] ) && char_is_space( scanner[ 1 ] ) ) + { + string_append_c_str_len( & content, cut_ptr, cut_length ); + do + { + move_fwd(); + } + while ( tokleft && char_is_space( scanner[0] ) ); + + last_cut = rcast( sptr, scanner ) - rcast( sptr, raw_text.Ptr ); + + // Preserve only 1 space of formattting + char* last = string_back(content); + if ( last == nullptr || * last != ' ' ) + string_append_char( & content, ' ' ); + + continue; + } + + move_fwd(); + } + + if ( last_cut < raw_text.Len ) + { + string_append_c_str_len( & content, cut_ptr, raw_text.Len - last_cut ); + } + +#undef cut_ptr +#undef cut_length +#undef pos +#undef move_fwd + + return content; +} + +internal +Code parse_array_decl() +{ + push_scope(); + + if ( check( Tok_Operator ) && currtok.Text[0] == '[' && currtok.Text[1] == ']' ) + { + Code array_expr = untyped_str( tok_to_str(currtok) ); + eat( Tok_Operator ); + // [] + + parser_pop(& Context); + return array_expr; + } + + if ( check( Tok_BraceSquare_Open ) ) + { + eat( Tok_BraceSquare_Open ); + // [ + + if ( left == 0 ) + { + log_failure( "Error, unexpected end of array declaration ( '[]' scope started )\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + if ( currtok.Type == Tok_BraceSquare_Close ) + { + log_failure( "Error, empty array expression in definition\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + Token untyped_tok = currtok; + + while ( left && currtok.Type != Tok_BraceSquare_Close ) + { + eat( currtok.Type ); + } + + untyped_tok.Length = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)untyped_tok.Text; + + Code array_expr = untyped_str( tok_to_str(untyped_tok) ); + // [ + + if ( left == 0 ) + { + log_failure( "Error, unexpected end of array declaration, expected ]\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + if ( currtok.Type != Tok_BraceSquare_Close ) + { + log_failure( "%s: Error, expected ] in array declaration, not %s\n%s", toktype_to_str( currtok.Type ), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + eat( Tok_BraceSquare_Close ); + // [ ] + + // Its a multi-dimensional array + if ( check( Tok_BraceSquare_Open )) + { + Code adjacent_arr_expr = parse_array_decl(); + // [ ][ ]... + + array_expr->Next = adjacent_arr_expr; + } + + parser_pop(& Context); + return array_expr; + } + + parser_pop(& Context); + return NullCode; +} + +internal inline +CodeAttributes parse_attributes() +{ + push_scope(); + + Token start = currtok; + s32 len = 0; + + // There can be more than one attribute. If there is flatten them to a single string. + // TODO(Ed): Support keeping an linked list of attributes similar to parameters + while ( left && tok_is_attribute(currtok) ) + { + if ( check( Tok_Attribute_Open ) ) + { + eat( Tok_Attribute_Open ); + // [[ + + while ( left && currtok.Type != Tok_Attribute_Close ) + { + eat( currtok.Type ); + } + // [[ + + eat( Tok_Attribute_Close ); + // [[ ]] + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( check( Tok_Decl_GNU_Attribute ) ) + { + eat( Tok_Decl_GNU_Attribute ); + eat( Tok_Capture_Start ); + eat( Tok_Capture_Start ); + // __attribute__(( + + while ( left && currtok.Type != Tok_Capture_End ) + { + eat( currtok.Type ); + } + // __attribute__(( + + eat( Tok_Capture_End ); + eat( Tok_Capture_End ); + // __attribute__(( )) + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( check( Tok_Decl_MSVC_Attribute ) ) + { + eat( Tok_Decl_MSVC_Attribute ); + eat( Tok_Capture_Start ); + // __declspec( + + while ( left && currtok.Type != Tok_Capture_End ) + { + eat( currtok.Type ); + } + // __declspec( + + eat( Tok_Capture_End ); + // __declspec( ) + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + } + else if ( tok_is_attribute(currtok) ) + { + eat( currtok.Type ); + // + + // If its a macro based attribute, this could be a functional macro such as Unreal's UE_DEPRECATED(...) + if ( check( Tok_Capture_Start)) + { + eat( Tok_Capture_Start ); + + s32 level = 0; + while (left && currtok.Type != Tok_Capture_End && level == 0) + { + if (currtok.Type == Tok_Capture_Start) + ++ level; + if (currtok.Type == Tok_Capture_End) + --level; + eat(currtok.Type); + } + eat(Tok_Capture_End); + } + + len = ( ( sptr )prevtok.Text + prevtok.Length ) - ( sptr )start.Text; + // ( ... ) + } + } + + if ( len > 0 ) + { + StrC attribute_txt = { len, start.Text }; + parser_pop(& Context); + + String name_stripped = parser_strip_formatting( attribute_txt, parser_strip_formatting_dont_preserve_newlines ); + + Code result = make_code(); + result->Type = CT_PlatformAttributes; + result->Name = get_cached_string( string_to_strc(name_stripped) ); + result->Content = result->Name; + // result->Token = + + return ( CodeAttributes )result; + } + + parser_pop(& Context); + return NullCode; +} + +internal +Code parse_class_struct( TokType which, bool inplace_def ) +{ + if ( which != Tok_Decl_Class && which != Tok_Decl_Struct ) + { + log_failure( "Error, expected class or struct, not %s\n%s", toktype_to_str( which ), parser_to_string(Context) ); + return InvalidCode; + } + + Token name = { nullptr, 0, Tok_Invalid }; + + AccessSpec access = AccessSpec_Default; + CodeTypename parent = { nullptr }; + CodeBody body = { nullptr }; + CodeAttributes attributes = { nullptr }; + ModuleFlag mflags = ModuleFlag_None; + + Code result = InvalidCode; + + if ( check(Tok_Module_Export) ) + { + mflags = ModuleFlag_Export; + eat( Tok_Module_Export ); + } + // + + eat( which ); + // + + attributes = parse_attributes(); + // + + if ( check( Tok_Identifier ) ) + { + name = parse_identifier(nullptr); + Context.Scope->Name = name; + } + // + + local_persist + char interface_arr_mem[ kilobytes(4) ] = {0}; + Array(CodeTypename) interfaces; { + Arena arena = arena_init_from_memory( interface_arr_mem, kilobytes(4) ); + interfaces = array_init_reserve(CodeTypename, arena_allocator_info(& arena), 4 ); + } + + // TODO(Ed) : Make an AST_DerivedType, we'll store any arbitary derived type into there as a linear linked list of them. + if ( check( Tok_Assign_Classifer ) ) + { + eat( Tok_Assign_Classifer ); + // : + + if ( tok_is_access_specifier(currtok) ) + { + access = tok_to_access_specifier(currtok); + // : + eat( currtok.Type ); + } + + Token parent_tok = parse_identifier(nullptr); + parent = def_type( tok_to_str(parent_tok) ); + // : + + while ( check(Tok_Comma) ) + { + eat( Tok_Comma ); + // : , + + if ( tok_is_access_specifier(currtok) ) + { + eat(currtok.Type); + } + Token interface_tok = parse_identifier(nullptr); + + array_append( interfaces, def_type( tok_to_str(interface_tok) ) ); + // : , ... + } + } + + if ( check( Tok_BraceCurly_Open ) ) + { + body = parse_class_struct_body( which, name ); + } + // : , ... { } + + CodeComment inline_cmt = NullCode; + if ( ! inplace_def ) + { + Token stmt_end = currtok; + eat( Tok_Statement_End ); + // : , ... { }; + + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // : , ... { }; + } + + if ( which == Tok_Decl_Class ) + result = cast(Code, def_class( tok_to_str(name), def_assign( body, parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); + + else + result = cast(Code, def_struct( tok_to_str(name), def_assign( body, (CodeTypename)parent, access, attributes, interfaces, scast(s32, array_num(interfaces)), mflags ) )); + + if ( inline_cmt ) + result->InlineCmt = cast(Code, inline_cmt); + + array_free(interfaces); + return result; +} + +internal neverinline +CodeBody parse_class_struct_body( TokType which, Token name ) +{ + push_scope(); + + eat( Tok_BraceCurly_Open ); + // { + + CodeBody + result = (CodeBody) make_code(); + + if ( which == Tok_Decl_Class ) + result->Type = CT_Class_Body; + + else + result->Type = CT_Struct_Body; + + while ( left && currtok_noskip.Type != Tok_BraceCurly_Close ) + { + Code member = Code_Invalid; + CodeAttributes attributes = { nullptr }; + CodeSpecifiers specifiers = { nullptr }; + + bool expects_function = false; + + // Context.Scope->Start = currtok_noskip; + + if ( currtok_noskip.Type == Tok_Preprocess_Hash ) + eat( Tok_Preprocess_Hash ); + + b32 macro_found = true; + + switch ( currtok_noskip.Type ) + { + case Tok_Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %S\n", tok_to_string(currtok_noskip)); + eat( Tok_Statement_End ); + continue; + } + case Tok_NewLine: + member = fmt_newline; + eat( Tok_NewLine ); + break; + + case Tok_Comment: + member = cast(Code, parse_comment()); + break; + + case Tok_Access_Public: + member = access_public; + eat( Tok_Access_Public ); + eat( Tok_Assign_Classifer ); + // public: + break; + + case Tok_Access_Protected: + member = access_protected; + eat( Tok_Access_Protected ); + eat( Tok_Assign_Classifer ); + // protected: + break; + + case Tok_Access_Private: + member = access_private; + eat( Tok_Access_Private ); + eat( Tok_Assign_Classifer ); + // private: + break; + + case Tok_Decl_Class: + member = parse_complicated_definition( Tok_Decl_Class ); + // class + break; + + case Tok_Decl_Enum: + member = parse_complicated_definition( Tok_Decl_Enum ); + // enum + break; + + case Tok_Decl_Friend: + member = cast(Code, parser_parse_friend()); + // friend + break; + + case Tok_Decl_Operator: + member = cast(Code, parser_parse_operator_cast(NullCode)); + // operator () + break; + + case Tok_Decl_Struct: + member = parse_complicated_definition( Tok_Decl_Struct ); + // struct + break; + + case Tok_Decl_Template: + member = cast(Code, parser_parse_template()); + // template< ... > + break; + + case Tok_Decl_Typedef: + member = cast(Code, parser_parse_typedef()); + // typedef + break; + + case Tok_Decl_Union: + member = parse_complicated_definition( Tok_Decl_Union ); + // union + break; + + case Tok_Decl_Using: + member = cast(Code, parser_parse_using()); + // using + break; + + case Tok_Operator: + //if ( currtok.Text[0] != '~' ) + //{ + // log_failure( "Operator token found in global body but not destructor unary negation\n%s", to_string(Context) ); + // return InvalidCode; + //} + + member = cast(Code, parser_parse_destructor(NullCode)); + // ~() + break; + + case Tok_Preprocess_Define: + member = cast(Code, parse_define()); + // #define + break; + + case Tok_Preprocess_Include: + member = cast(Code, parse_include()); + // #include + break; + + case Tok_Preprocess_If: + case Tok_Preprocess_IfDef: + case Tok_Preprocess_IfNotDef: + case Tok_Preprocess_ElIf: + member = cast(Code, parse_preprocess_cond()); + // # + break; + + case Tok_Preprocess_Else: + member = cast(Code, preprocess_else); + eat( Tok_Preprocess_Else ); + // #else + break; + + case Tok_Preprocess_EndIf: + member = cast(Code, preprocess_endif); + eat( Tok_Preprocess_EndIf ); + // #endif + break; + + case Tok_Preprocess_Macro: + // + macro_found = true; + goto Preprocess_Macro_Bare_In_Body; + break; + + case Tok_Preprocess_Pragma: + member = cast(Code, parse_pragma()); + // #pragma + break; + + case Tok_Preprocess_Unsupported: + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Unsupported, parser_consume_braces )); + // # + break; + + case Tok_StaticAssert: + member = parse_static_assert(); + // static_assert + break; + + case Tok_Attribute_Open: + case Tok_Decl_GNU_Attribute: + case Tok_Decl_MSVC_Attribute: + #define Entry( attribute, str ) case attribute: + GEN_DEFINE_ATTRIBUTE_TOKENS + #undef Entry + { + attributes = parse_attributes(); + // + } + //! Fallthrough intended + case Tok_Spec_Consteval: + case Tok_Spec_Constexpr: + case Tok_Spec_Constinit: + case Tok_Spec_Explicit: + case Tok_Spec_ForceInline: + case Tok_Spec_Inline: + case Tok_Spec_Mutable: + case Tok_Spec_NeverInline: + case Tok_Spec_Static: + case Tok_Spec_Volatile: + case Tok_Spec_Virtual: + { + Specifier specs_found[16] = { Spec_NumSpecifiers }; + s32 NumSpecifiers = 0; + + while ( left && tok_is_specifier(currtok) ) + { + Specifier spec = strc_to_specifier( tok_to_str(currtok) ); + + b32 ignore_spec = false; + + switch ( spec ) + { + case Spec_Constexpr: + case Spec_Constinit: + case Spec_Explicit: + case Spec_Inline: + case Spec_ForceInline: + case Spec_Mutable: + case Spec_NeverInline: + case Spec_Static: + case Spec_Volatile: + case Spec_Virtual: + break; + + case Spec_Consteval: + expects_function = true; + break; + + case Spec_Const : + ignore_spec = true; + break; + + default: + log_failure( "Invalid specifier %s for variable\n%s", spec_to_str(spec), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + // Every specifier after would be considered part of the type type signature + if (ignore_spec) + break; + + specs_found[NumSpecifiers] = spec; + NumSpecifiers++; + eat( currtok.Type ); + } + + if ( NumSpecifiers ) + { + specifiers = def_specifiers( NumSpecifiers, specs_found ); + } + // + + if ( tok_is_attribute(currtok) ) + { + // Unfortuantely Unreal has code where there is attirbutes before specifiers + CodeAttributes more_attributes = parse_attributes(); + + if ( attributes ) + { + String fused = string_make_reserve( GlobalAllocator, attributes->Content.Len + more_attributes->Content.Len ); + string_append_fmt( & fused, "%S %S", attributes->Content, more_attributes->Content ); + + StrC attrib_name = { string_length(fused), fused }; + attributes->Name = get_cached_string( attrib_name ); + attributes->Content = attributes->Name; + // + } + + attributes = more_attributes; + } + + if ( currtok.Type == Tok_Operator && currtok.Text[0] == '~' ) + { + member = cast(Code, parser_parse_destructor( specifiers )); + // ~() + break; + } + + if ( currtok.Type == Tok_Decl_Operator ) + { + member = cast(Code, parser_parse_operator_cast( specifiers )); + // operator () + break; + } + } + //! Fallthrough intentional + case Tok_Identifier: + case Tok_Spec_Const: + case Tok_Type_Unsigned: + case Tok_Type_Signed: + case Tok_Type_Short: + case Tok_Type_Long: + case Tok_Type_bool: + case Tok_Type_char: + case Tok_Type_int: + case Tok_Type_double: + { + if ( nexttok.Type == Tok_Capture_Start && name.Length && currtok.Type == Tok_Identifier ) + { + if ( str_compare_len( name.Text, currtok.Text, name.Length ) == 0 ) + { + member = cast(Code, parser_parse_constructor( specifiers )); + // () + break; + } + } + + if (macro_found) + { + Preprocess_Macro_Bare_In_Body: + b32 lone_macro = nexttok.Type == Tok_Statement_End || nexttok_noskip.Type == Tok_NewLine; + if (lone_macro) + { + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Macro, parser_consume_braces )); + // ; + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + continue; + } + + // We have a macro but its most likely behaving as a typename + // operator ... + // or + // ... + } + break; + + default: + Token untyped_tok = currtok; + + while ( left && currtok.Type != Tok_BraceCurly_Close ) + { + untyped_tok.Length = ( (sptr)currtok.Text + currtok.Length ) - (sptr)untyped_tok.Text; + eat( currtok.Type ); + } + + member = untyped_str( tok_to_str(untyped_tok) ); + // Something unknown + break; + } + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + body_append(result, member ); + } + + eat( Tok_BraceCurly_Close ); + // { } + parser_pop(& Context); + return result; +} + +internal +CodeComment parse_comment() +{ + push_scope(); + + CodeComment + result = (CodeComment) make_code(); + result->Type = CT_Comment; + result->Content = get_cached_string( tok_to_str(currtok_noskip) ); + result->Name = result->Content; + // result->Token = currtok_noskip; + eat( Tok_Comment ); + + parser_pop(& Context); + return result; +} + +internal +Code parse_complicated_definition( TokType which ) +{ + push_scope(); + + bool is_inplace = false; + + TokArray tokens = Context.Tokens; + + s32 idx = tokens.Idx; + s32 level = 0; + for ( ; idx < array_num(tokens.Arr); idx++ ) + { + if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Open ) + level++; + + if ( tokens.Arr[ idx ].Type == Tok_BraceCurly_Close ) + level--; + + if ( level == 0 && tokens.Arr[ idx ].Type == Tok_Statement_End ) + break; + } + + if ( ( idx - 2 ) == tokens.Idx ) + { + // Its a forward declaration only + Code result = parse_forward_or_definition( which, is_inplace ); + // ; + parser_pop(& Context); + return result; + } + + Token tok = tokens.Arr[ idx - 1 ]; + if ( tok_is_specifier(tok) && spec_is_trailing( strc_to_specifier( tok_to_str(tok))) ) + { + // (...) ...; + + s32 spec_idx = idx - 1; + Token spec = tokens.Arr[spec_idx]; + while ( tok_is_specifier(spec) && spec_is_trailing( strc_to_specifier( tok_to_str(spec))) ) + { + -- spec_idx; + spec = tokens.Arr[spec_idx]; + } + + if ( tokens.Arr[spec_idx].Type == Tok_Capture_End ) + { + // Forward declaration with trailing specifiers for a procedure + tok = tokens.Arr[spec_idx]; + + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); + // , or Name> ... + parser_pop(& Context); + return result; + } + + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + if ( tok.Type == Tok_Identifier ) + { + tok = tokens.Arr[ idx - 2 ]; + bool is_indirection = tok.Type == Tok_Ampersand || tok.Type == Tok_Star; + bool ok_to_parse = false; + + if ( tok.Type == Tok_BraceCurly_Close ) + { + // Its an inplace definition + // { ... } ; + ok_to_parse = true; + is_inplace = true; + } + else if ( tok.Type == Tok_Identifier && tokens.Arr[ idx - 3 ].Type == which ) + { + // Its a variable with type ID using namespace. + // ; + ok_to_parse = true; + } + else if ( tok.Type == Tok_Assign_Classifer + && ( ( tokens.Arr[idx - 5].Type == which && tokens.Arr[idx - 4].Type == Tok_Decl_Class ) + || ( tokens.Arr[idx - 4].Type == which)) + ) + { + // Its a forward declaration of an enum + // : ; + // : ; + ok_to_parse = true; + Code result = cast(Code, parser_parse_enum( ! parser_inplace_def)); + parser_pop(& Context); + return result; + } + else if ( is_indirection ) + { + // Its a indirection type with type ID using struct namespace. + // * ; + ok_to_parse = true; + } + + if ( ! ok_to_parse ) + { + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); + // , or Name> ... + parser_pop(& Context); + return result; + } + else if ( tok.Type >= Tok_Type_Unsigned && tok.Type <= Tok_Type_MS_W64 ) + { + tok = tokens.Arr[ idx - 2 ]; + + if ( tok.Type != Tok_Assign_Classifer + || ( ( tokens.Arr[idx - 5].Type != which && tokens.Arr[idx - 4].Type != Tok_Decl_Class ) + && ( tokens.Arr[idx - 4].Type != which)) + ) + { + log_failure( "Unsupported or bad member definition after %s declaration\n%s", toktype_to_str(which), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + // Its a forward declaration of an enum class + // : ; + // : ; + Code result = cast(Code, parser_parse_enum( ! parser_inplace_def)); + parser_pop(& Context); + return result; + } + else if ( tok.Type == Tok_BraceCurly_Close ) + { + // Its a definition + Code result = parse_forward_or_definition( which, is_inplace ); + // { ... }; + parser_pop(& Context); + return result; + } + else if ( tok.Type == Tok_BraceSquare_Close ) + { + // Its an array definition + Code result = parse_operator_function_or_variable( false, NullCode, NullCode ); + // [ ... ]; + parser_pop(& Context); + return result; + } + else + { + log_failure( "Unsupported or bad member definition after %s declaration\n%S", toktype_to_str(which).Ptr, parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } +} + +internal inline +CodeDefine parse_define() +{ + push_scope(); + eat( Tok_Preprocess_Define ); + // #define + + CodeDefine + define = (CodeDefine) make_code(); + define->Type = CT_Preprocess_Define; + + if ( ! check( Tok_Identifier ) ) + { + log_failure( "Error, expected identifier after #define\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + Context.Scope->Name = currtok; + define->Name = get_cached_string( tok_to_str(currtok) ); + eat( Tok_Identifier ); + // #define + + if ( ! check( Tok_Preprocess_Content )) + { + log_failure( "Error, expected content after #define %s\n%s", define->Name, parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + if ( currtok.Length == 0 ) + { + define->Content = get_cached_string( tok_to_str(currtok) ); + eat( Tok_Preprocess_Content ); + // #define + + parser_pop(& Context); + return define; + } + + define->Content = get_cached_string( string_to_strc( parser_strip_formatting( tok_to_str(currtok), parser_strip_formatting_dont_preserve_newlines )) ); + eat( Tok_Preprocess_Content ); + // #define + + parser_pop(& Context); + return define; +} + +internal inline +Code parse_assignment_expression() +{ + Code expr = { nullptr }; + + eat( Tok_Operator ); + // = + + Token expr_tok = currtok; + + if ( currtok.Type == Tok_Statement_End && currtok.Type != Tok_Comma ) + { + log_failure( "Expected expression after assignment operator\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + s32 level = 0; + while ( left && currtok.Type != Tok_Statement_End && (currtok.Type != Tok_Comma || level > 0) ) + { + if (currtok.Type == Tok_BraceCurly_Open ) + level++; + if (currtok.Type == Tok_BraceCurly_Close ) + level--; + if (currtok.Type == Tok_Capture_Start) + level++; + else if (currtok.Type == Tok_Capture_End) + level--; + + eat( currtok.Type ); + } + + expr_tok.Length = ( ( sptr )currtok.Text + currtok.Length ) - ( sptr )expr_tok.Text - 1; + expr = untyped_str( tok_to_str(expr_tok) ); + // = + return expr; +} + +internal inline +Code parse_forward_or_definition( TokType which, bool is_inplace ) +{ + Code result = InvalidCode; + + switch ( which ) + { + case Tok_Decl_Class: + result = cast(Code, parser_parse_class( is_inplace )); + return result; + + case Tok_Decl_Enum: + result = cast(Code, parser_parse_enum( is_inplace )); + return result; + + case Tok_Decl_Struct: + result = cast(Code, parser_parse_struct( is_inplace )); + return result; + + case Tok_Decl_Union: + result = cast(Code, parser_parse_union( is_inplace )); + return result; + + default: + log_failure( "Error, wrong token type given to parse_complicated_definition " + "(only supports class, enum, struct, union) \n%s" + , parser_to_string(Context) ); + + return InvalidCode; + } +} + +// Function parsing is handled in multiple places because its initial signature is shared with variable parsing +internal inline +CodeFn parse_function_after_name( + ModuleFlag mflags + , CodeAttributes attributes + , CodeSpecifiers specifiers + , CodeTypename ret_type + , Token name +) +{ + push_scope(); + CodeParams params = parse_params(parser_use_parenthesis); + // ( ) + + // TODO(Ed), Review old comment : These have to be kept separate from the return type's specifiers. + while ( left && tok_is_specifier(currtok) ) + { + if ( specifiers == nullptr ) + { + specifiers = def_specifier( strc_to_specifier( tok_to_str(currtok)) ); + eat( currtok.Type ); + continue; + } + + specifiers_append(specifiers, strc_to_specifier( tok_to_str(currtok)) ); + eat( currtok.Type ); + } + // ( ) + + CodeBody body = NullCode; + CodeComment inline_cmt = NullCode; + if ( check( Tok_BraceCurly_Open ) ) + { + body = cast(CodeBody, parse_function_body()); + if ( cast(Code, body) == Code_Invalid ) + { + parser_pop(& Context); + return InvalidCode; + } + // ( ) { } + } + else if ( check(Tok_Operator) && currtok.Text[0] == '=' ) + { + eat(Tok_Operator); + specifiers_append(specifiers, Spec_Pure ); + + eat( Tok_Number); + Token stmt_end = currtok; + eat( Tok_Statement_End ); + // ( ) = 0; + + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // ( ) ; + } + else + { + Token stmt_end = currtok; + eat( Tok_Statement_End ); + // ( ) ; + + if ( currtok_noskip.Type == Tok_Comment && currtok_noskip.Line == stmt_end.Line ) + inline_cmt = parse_comment(); + // ( ) ; + } + + String + name_stripped = string_make_strc( GlobalAllocator, tok_to_str(name) ); + strip_space(name_stripped); + + CodeFn + result = (CodeFn) make_code(); + result->Name = get_cached_string( string_to_strc(name_stripped) ); + result->ModuleFlags = mflags; + + if ( body ) + { + switch ( body->Type ) + { + case CT_Function_Body: + case CT_Untyped: + break; + + default: + { + log_failure("Body must be either of Function_Body or Untyped type, %s\n%s", code_debug_str(body), parser_to_string(Context)); + parser_pop(& Context); + return InvalidCode; + } + } + + result->Type = CT_Function; + result->Body = body; + } + else + { + result->Type = CT_Function_Fwd; + } + + if ( attributes ) + result->Attributes = attributes; + + if ( specifiers ) + result->Specs = specifiers; + + result->ReturnType = ret_type; + + if ( params ) + result->Params = params; + + if ( inline_cmt ) + result->InlineCmt = inline_cmt; + + parser_pop(& Context); + return result; +} + +internal +Code parse_function_body() +{ + push_scope(); + + eat( Tok_BraceCurly_Open ); + + CodeBody + result = (CodeBody) make_code(); + result->Type = CT_Function_Body; + + // TODO : Support actual parsing of function body + Token start = currtok_noskip; + + s32 level = 0; + while ( left && ( currtok_noskip.Type != Tok_BraceCurly_Close || level > 0 ) ) + { + if ( currtok_noskip.Type == Tok_BraceCurly_Open ) + level++; + + else if ( currtok_noskip.Type == Tok_BraceCurly_Close && level > 0 ) + level--; + + eat( currtok_noskip.Type ); + } + + Token past = prevtok; + + s32 len = ( (sptr)prevtok.Text + prevtok.Length ) - (sptr)start.Text; + + if ( len > 0 ) + { + StrC str = { len, start.Text }; + body_append( result, cast(Code, def_execution( str )) ); + } + + eat( Tok_BraceCurly_Close ); + + parser_pop(& Context); + return cast(Code, result); +} + +internal neverinline +CodeBody parse_global_nspace( CodeType which ) +{ + push_scope(); + + if ( which != CT_Namespace_Body && which != CT_Global_Body && which != CT_Export_Body && which != CT_Extern_Linkage_Body ) + return InvalidCode; + + if ( which != CT_Global_Body ) + eat( Tok_BraceCurly_Open ); + // { + + CodeBody + result = (CodeBody) make_code(); + result->Type = which; + + while ( left && currtok_noskip.Type != Tok_BraceCurly_Close ) + { + Code member = Code_Invalid; + CodeAttributes attributes = { nullptr }; + CodeSpecifiers specifiers = { nullptr }; + + bool expects_function = false; + + // Context.Scope->Start = currtok_noskip; + + if ( currtok_noskip.Type == Tok_Preprocess_Hash ) + eat( Tok_Preprocess_Hash ); + + b32 macro_found = false; + + switch ( currtok_noskip.Type ) + { + case Tok_Comma: + { + log_failure("Dangling comma found: %S\nContext:\n%S", tok_to_string(currtok), parser_to_string(Context)); + parser_pop( & Context); + return InvalidCode; + } + break; + case Tok_Statement_End: + { + // TODO(Ed): Convert this to a general warning procedure + log_fmt("Dangling end statement found %S\n", tok_to_string(currtok_noskip)); + eat( Tok_Statement_End ); + continue; + } + case Tok_NewLine: + // Empty lines are auto skipped by Tokens.current() + member = fmt_newline; + eat( Tok_NewLine ); + break; + + case Tok_Comment: + member = cast(Code, parse_comment()); + break; + + case Tok_Decl_Class: + member = parse_complicated_definition( Tok_Decl_Class ); + // class + break; + + case Tok_Decl_Enum: + member = parse_complicated_definition( Tok_Decl_Enum ); + // enum + break; + + case Tok_Decl_Extern_Linkage: + if ( which == CT_Extern_Linkage_Body ) + log_failure( "Nested extern linkage\n%s", parser_to_string(Context) ); + + member = cast(Code, parser_parse_extern_link()); + // extern "..." { ... } + break; + + case Tok_Decl_Namespace: + member = cast(Code, parser_parse_namespace()); + // namespace { ... } + break; + + case Tok_Decl_Struct: + member = parse_complicated_definition( Tok_Decl_Struct ); + // struct ... + break; + + case Tok_Decl_Template: + member = cast(Code, parser_parse_template()); + // template<...> ... + break; + + case Tok_Decl_Typedef: + member = cast(Code, parser_parse_typedef()); + // typedef ... + break; + + case Tok_Decl_Union: + member = parse_complicated_definition( Tok_Decl_Union ); + // union ... + break; + + case Tok_Decl_Using: + member = cast(Code, parser_parse_using()); + // using ... + break; + + case Tok_Preprocess_Define: + member = cast(Code, parse_define()); + // #define ... + break; + + case Tok_Preprocess_Include: + member = cast(Code, parse_include()); + // #include ... + break; + + case Tok_Preprocess_If: + case Tok_Preprocess_IfDef: + case Tok_Preprocess_IfNotDef: + case Tok_Preprocess_ElIf: + member = cast(Code, parse_preprocess_cond()); + // # ... + break; + + case Tok_Preprocess_Else: + member = cast(Code, preprocess_else); + eat( Tok_Preprocess_Else ); + // #else + break; + + case Tok_Preprocess_EndIf: + member = cast(Code, preprocess_endif); + eat( Tok_Preprocess_EndIf ); + // #endif + break; + + case Tok_Preprocess_Macro: { + // + macro_found = true; + goto Preprocess_Macro_Bare_In_Body; + } + break; + + case Tok_Preprocess_Pragma: { + member = cast(Code, parse_pragma()); + // #pragma ... + } + break; + + case Tok_Preprocess_Unsupported: { + member = cast(Code, parse_simple_preprocess( Tok_Preprocess_Unsupported, parser_consume_braces )); + // # ... + } + break; + + case Tok_StaticAssert: { + member = cast(Code, parse_static_assert()); + // static_assert( , ... ); + } + break; + + case Tok_Module_Export: { + if ( which == CT_Export_Body ) + log_failure( "Nested export declaration\n%s", parser_to_string(Context) ); + + member = cast(Code, parser_parse_export_body()); + // export { ... } + } + break; + + case Tok_Module_Import: { + not_implemented( context ); + // import ... + } + //! Fallthrough intentional + case Tok_Attribute_Open: + case Tok_Decl_GNU_Attribute: + case Tok_Decl_MSVC_Attribute: + #define Entry( attribute, str ) case attribute: + GEN_DEFINE_ATTRIBUTE_TOKENS + #undef Entry + { + attributes = parse_attributes(); + // + } + //! Fallthrough intentional + case Tok_Spec_Consteval: + case Tok_Spec_Constexpr: + case Tok_Spec_Constinit: + case Tok_Spec_Extern: + case Tok_Spec_ForceInline: + case Tok_Spec_Global: + case Tok_Spec_Inline: + case Tok_Spec_Internal_Linkage: + case Tok_Spec_NeverInline: + case Tok_Spec_Static: + { + Specifier specs_found[16] = { Spec_NumSpecifiers }; + s32 NumSpecifiers = 0; + + while ( left && tok_is_specifier(currtok) ) + { + Specifier spec = strc_to_specifier( tok_to_str(currtok) ); + + bool ignore_spec = false; + + switch ( spec ) + { + case Spec_Constexpr: + case Spec_Constinit: + case Spec_ForceInline: + case Spec_Global: + case Spec_External_Linkage: + case Spec_Internal_Linkage: + case Spec_Inline: + case Spec_Mutable: + case Spec_NeverInline: + case Spec_Static: + case Spec_Volatile: + break; + + case Spec_Consteval: + expects_function = true; + break; + + case Spec_Const: + ignore_spec = true; + break; + + default: + StrC spec_str = spec_to_str(spec); + + log_failure( "Invalid specifier %.*s for variable\n%s", spec_str.Len, spec_str, parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + if (ignore_spec) + break; + + specs_found[NumSpecifiers] = spec; + NumSpecifiers++; + eat( currtok.Type ); + } + + if ( NumSpecifiers ) + { + specifiers = def_specifiers( NumSpecifiers, specs_found ); + } + // + } + //! Fallthrough intentional + case Tok_Identifier: + case Tok_Spec_Const: + case Tok_Type_Long: + case Tok_Type_Short: + case Tok_Type_Signed: + case Tok_Type_Unsigned: + case Tok_Type_bool: + case Tok_Type_char: + case Tok_Type_double: + case Tok_Type_int: + { + // This s only in a scope so that Preprocess_Macro_Bare_In_Body works without microsoft extension warnings + { + Code constructor_destructor = parse_global_nspace_constructor_destructor( specifiers ); + // Possible constructor implemented at global file scope. + if ( constructor_destructor ) + { + member = constructor_destructor; + break; + } + + bool found_operator_cast_outside_class_implmentation = false; + s32 idx = Context.Tokens.Idx; + + for ( ; idx < array_num(Context.Tokens.Arr); idx++ ) + { + Token tok = Context.Tokens.Arr[ idx ]; + + if ( tok.Type == Tok_Identifier ) + { + idx++; + tok = Context.Tokens.Arr[ idx ]; + if ( tok.Type == Tok_Access_StaticSymbol ) + continue; + + break; + } + + if ( tok.Type == Tok_Decl_Operator ) + found_operator_cast_outside_class_implmentation = true; + + break; + } + + if ( found_operator_cast_outside_class_implmentation ) + { + member = cast(Code, parser_parse_operator_cast( specifiers )); + // ::operator () { ... } + break; + } + } + + if (macro_found) + { + Preprocess_Macro_Bare_In_Body: + b32 lone_macro = nexttok.Type == Tok_Statement_End || nexttok_noskip.Type == Tok_NewLine; + if (lone_macro) + { + member = parse_simple_preprocess( Tok_Preprocess_Macro, parser_consume_braces ); + // ; + + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\n%s", parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + goto Member_Resolved_To_Lone_Macro; + } + + // We have a macro but its most likely behaving as a typename + // ... + } + } + + Member_Resolved_To_Lone_Macro: + if ( member == Code_Invalid ) + { + log_failure( "Failed to parse member\nToken: %S\nContext:\n%S", tok_to_string(currtok_noskip), parser_to_string(Context) ); + parser_pop(& Context); + return InvalidCode; + } + + // log_fmt("Global Body Member: %s", member->debug_str()); + body_append(result, member ); + } + + if ( which != CT_Global_Body ) + eat( Tok_BraceCurly_Close ); + // { } + + parser_pop(& Context); + return result; +} + +internal inline +Code parse_global_nspace_constructor_destructor( CodeSpecifiers specifiers ) +{ + Code result = { nullptr }; + + /* + To check if a definition is for a constructor we can go straight to the opening parenthesis for its parameters + From There we work backwards to see if we come across two identifiers with the same name between an member access + :: operator, there can be template parameters on the left of the :: so we ignore those. + Whats important is that its back to back. + + This has multiple possible faults. What we parse using this method may not filter out if something has a "return type" + This is bad since technically you could have a namespace nested into another namespace with the same name. + If this awful pattern is done the only way to distiguish with this coarse parse is to know there is no return type defined. + + TODO(Ed): We could fix this by attempting to parse a type, but we would have to have a way to have it soft fail and rollback. + */ + TokArray tokens = Context.Tokens; + + s32 idx = tokens.Idx; + Token nav = tokens.Arr[ idx ]; + for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[ idx ] ) + { + if ( nav.Text[0] == '<' ) + { + // Skip templated expressions as they mey have expressions with the () operators + s32 capture_level = 0; + s32 template_level = 0; + for ( ; idx < array_num(tokens.Arr); idx++, nav = tokens.Arr[idx] ) + { + if (nav.Text[ 0 ] == '<') + ++ template_level; + + if (nav.Text[ 0 ] == '>') + -- template_level; + if (nav.Type == Tok_Operator && nav.Text[1] == '>') + -- template_level; + + if ( nav.Type == Tok_Capture_Start) + { + if (template_level != 0 ) + ++ capture_level; + else + break; + } + + if ( template_level != 0 && nav.Type == Tok_Capture_End) + -- capture_level; + } + } + + if ( nav.Type == Tok_Capture_Start ) + break; + } + + -- idx; + Token tok_right = tokens.Arr[idx]; + Token tok_left = NullToken; + + if (tok_right.Type != Tok_Identifier) + { + // We're not dealing with a constructor if there is no identifier right before the opening of a parameter's scope. + return result; + } + + -- idx; + tok_left = tokens.Arr[idx]; + // ... + + bool possible_destructor = false; + if ( tok_left.Type == Tok_Operator && tok_left.Text[0] == '~') + { + possible_destructor = true; + -- idx; + tok_left = tokens.Arr[idx]; + } + + if ( tok_left.Type != Tok_Access_StaticSymbol ) + return result; + + -- idx; + tok_left = tokens.Arr[idx]; + // ... :: + + // We search toward the left until we find the next valid identifier + s32 capture_level = 0; + s32 template_level = 0; + while ( idx != tokens.Idx ) + { + if (tok_left.Text[ 0 ] == '<') + ++ template_level; + + if (tok_left.Text[ 0 ] == '>') + -- template_level; + if (tok_left.Type == Tok_Operator && tok_left.Text[1] == '>') + -- template_level; + + if ( template_level != 0 && tok_left.Type == Tok_Capture_Start) + ++ capture_level; + + if ( template_level != 0 && tok_left.Type == Tok_Capture_End) + -- capture_level; + + if ( capture_level == 0 && template_level == 0 && tok_left.Type == Tok_Identifier ) + break; + + -- idx; + tok_left = tokens.Arr[idx]; + } + + bool is_same = str_compare_len( tok_right.Text, tok_left.Text, tok_right.Length ) == 0; + if (tok_left.Type == Tok_Identifier && is_same) + { + // We have found the pattern we desired + if (possible_destructor) + { + // :: ~ ( + result = cast(Code, parser_parse_destructor( specifiers )); + } + else { + // :: ( + result = cast(Code, parser_parse_constructor( specifiers )); + } + } + + return result; +} + +// TODO(Ed): I want to eventually change the identifier to its own AST type. +// This would allow distinction of the qualifier for a symbol :: +// This would also allow +internal +Token parse_identifier( bool* possible_member_function ) +{ + push_scope(); + + Token name = currtok; + Context.Scope->Name = name; + eat( Tok_Identifier ); + // + + parse_template_args( & name ); + //