diff --git a/pattern_language/SUMMARY.md b/pattern_language/SUMMARY.md index 41a3cbb..d16a8eb 100644 --- a/pattern_language/SUMMARY.md +++ b/pattern_language/SUMMARY.md @@ -13,6 +13,7 @@ * [In / Out Variables](core-language/in-out-variables.md) * [Attributes](core-language/attributes.md) * [Preprocessor](core-language/preprocessor.md) +* [Importing Modules](core-language/importing-modules.md) * [Comments](core-language/comments.md) * [Sections](core-language/sections.md) diff --git a/pattern_language/core-language/importing-modules.md b/pattern_language/core-language/importing-modules.md index 50295e2..c96f5e1 100644 --- a/pattern_language/core-language/importing-modules.md +++ b/pattern_language/core-language/importing-modules.md @@ -1,21 +1,63 @@ # Importing modules -For better separation of pattern code into logical sections, we can use the facilities provided by the `import` statement. This statement will include other files in the current pattern. The `import` keyword is followed by the path to the included module with the dot (`.`) as the folder separator. The file extension will be resolved automatically. The statement will try to import a module with extensions `.pat` and `.hexpat`. It searches for a given module inside the `includes` folder in your pattern search paths. The default search path is in the `includes` folder inside ImHex's installation folder. Additional search paths can be added in the `Extras > Settings > Folders` menu. +Patterns can be split into multiple files to better separate pattern code into logical sections. To import other files into the current file, pattern language provides two facilities: the `#include` directive and the `import` statement. Both will search for a given file inside the `includes` folder in pattern search paths. The default search paths are: + +* The `includes` folder inside the ImHex installation directory. +* The `AppData/Local/imhex/includes` directory. +* Additional search paths. To add additional search paths go to `Extras > Settings > Folders` menu. + +### `#include` directive + +A [preprocessor directive](preprocessor.md). The preprocessor replaces this directive with all the lexical tokens from the included file *including* all the preprocessor defines. On inclusion, this system maintains its own list of files marked with [`#pragma once`](#include-guards). + +To use the `#include` directive, specify a path to the file to include followed by the file extension. The path can be enclosed in double quotes (`"path/filename.extension"`) or pointy braces (``). The extension is optional. The `#include` directive looks for a file with extensions `.pat` and `.hexpat` if none is specified. However, by convention, the extension is specified when including files. Both of the following are valid ways to use the `#include` directive: + +```rust +#include "std/io.pat" +#include +``` + +### `import` statement + +The `import` statement is processed during the parsing stage. Once the parser encounters this statement, a separate parser is created to parse the imported file as a separate compilation unit. It's then inserted into the abstract syntax tree (AST) of the current file. Because of this, the imported file can't use the types already declared in the current file, while included files can. The preprocessor defines *don't propagate* when using the `import` statement. + +The `import` keyword is followed by the path to the file to include with the dot (`.`) as the folder separator. The file extension will be resolved automatically. The statement looks for a file with extensions `.pat` and `.hexpat`. As with any other language statement, the line must end with a semicolon (`;`). ```rust import sys.mem; ``` -## Include guards +### Include guards -Files that can be imported to other files need to have include guards to prevent multiple inclusions. To do that, use the `#pragma once` preprocessor directive. The `import` statement will respect that define. +#### `#pragma once` directive -## Importing standard library modules +To prevent duplicate declarations, files meant for importing to other files can use the `#pragma once` directive to prevent multiple inclusions. **Important**, both `#include` directive and `import` statement keeps its own list of files marked with `#pragma once`. That means when a file is included in the current file, and then transitively imported by importing a different file, the current file would get duplicate declarations. In other words, a file should only ever be included by using one of the systems: the `#include` directive or the `import` statement to prevent duplicate declarations. -Standard library modules bundled with ImHex have their include guards respected by the `import` statement, but not by the `#include` preprocessor directive. To use standard library modules import them using the `import` statement. +#### Manual include guards + +When using `#include`, you can write include guards manually using `#ifndef` and `#define` directives: + +```C++ +#ifndef FOO_HEXPAT +#define FOO_HEXPAT + +// Pattern code + +#endif +``` + +#### Importing standard library headers + +The standard library headers all use the `import` statement internally, and as such should be imported using `import`. ```rust import std.io; import std.mem; import type.float16; ``` + +*Note* however, that this only pertains to standard library headers. Custom patterns can still import standard library headers while using `#include` for files that are part of the client project. + +### Forward declarations. + +The pattern language supports [forward declarations](data-types.md#forward-declaration). diff --git a/pattern_language/core-language/preprocessor.md b/pattern_language/core-language/preprocessor.md index 6dc6ea9..9936e53 100644 --- a/pattern_language/core-language/preprocessor.md +++ b/pattern_language/core-language/preprocessor.md @@ -16,7 +16,7 @@ This directive causes a find-and-replace to be performed. In the example above, #include ``` -This directive allows inclusion of other files into the current program. The content of the specified file gets copied directly into the current file. +This directive allows inclusion of other files into the current program. The content of the specified file gets copied directly into the current file. See [importing modules](importing-modules.md#include-directive) for more info. ### `#ifdef`, `#ifndef`, `#endif` @@ -76,13 +76,13 @@ This pragma automatically adjusts the base address of the currently loaded file. **Possible values:** Any integer value **Default:** `32` -This pragma sets the evaluation depth of recursive functions and types. To prevent the runtime from crashing when evaluating infinitely deep recursive types, execution will stop prematurely if it detects recursion that is too deep. This pragma can adjust the maximum depth allowed +This pragma sets the evaluation depth of recursive functions and types. To prevent the runtime from crashing when evaluating infinitely deep recursive types, execution will stop prematurely if it detects recursion that is too deep. This pragma can adjust the maximum depth allowed. #### `array_limit` **Possible values:** Any integer value **Default:** `0x1000` -This pragma sets the maximum number of entries allowed in an array. To prevent the runtime using up a lot of memory when creating huge arrays, execution will stop prematurely if an array with too many entries is evaluated. This pragma can adjust the maximum number of entries allowed +This pragma sets the maximum number of entries allowed in an array. To prevent the runtime using up a lot of memory when creating huge arrays, execution will stop prematurely if an array with too many entries is evaluated. This pragma can adjust the maximum number of entries allowed. #### `pattern_limit` @@ -96,11 +96,13 @@ This pragma takes no value and simply marks the current file to only be includab This is mainly useful to prevent functions, types and variables that are defined in that file, from being defined multiple times. +The `import` statement and `#include` directive each keep a separate list of files marked with `#pragma once`. That means that a set of headers using one system for importing should stick to it. See [Importing Modules](importing-modules.md) for more info. + #### `bitfield_order` **Possible values:** `right_to_left`, `left_to_right` **Default:** `right_to_left` -This pragma overrides the default bitfield bit order. It works the same as the `[[left_to_right]]` and `[[right_to_left]]` attributes but is automatically applied to all created bitfields +This pragma overrides the default bitfield bit order. It works the same as the `[[left_to_right]]` and `[[right_to_left]]` attributes but is automatically applied to all created bitfields. #### `debug`