#, instructing the compiler to perform specific actions, enforce checks, or modify parameters.
These directives can only be used at the outermost level of a source file and cannot be placed inside function definitions.
#include
The #include directive enables the inclusion of another FunC source file parsed in place of the directive.
Syntax:
<path_to_filename> is the path to the FunC source file to include.
Files are automatically checked for multiple inclusions.
By default, the compiler will ignore redundant inclusions if the same file is included more than once.
This also applies to inclusions along a path of nested inclusions.
A warning will be issued if the verbosity level is 2 or higher.
For example, suppose that main.fc contains the main function. Suppose also that main.fc includes a file A.fc, which in turn includes a file B.fc,
which in turn includes main.fc. When main.fc is compiled, the inclusion of main.fc in B.fc will be ignored.
If an error occurs while parsing an included file, the compiler displays an inclusion stack, showing the locations of each file in the inclusion chain.
#pragma
The #pragma directive provides additional information to the compiler beyond what the language conveys.
#pragma version
The #pragma version directive enforces using a specific FunC compiler version when compiling the file.
Syntax:
<op> is an optional version operator that allows to specify a constraint, and <sem_version> is specified
in semantic versioning (semver) format: a.b.c, where:
- a is the major version
- b is the minor version
- c is the patch version
2.3.4.
The second uses the greater than operator >, and it means that the compiler must have a version greater
than 2.3.4 (see precedence and operators below for details).
Equality and precedence
Two versions are equal if their respective major, minor, and patch numbers are equal. Two versions are not equal if at least one of those numbers differ. Example:- 1.2.3 is equal to 1.2.3
- 3.4.5 is not equal to 3.1.5
- If a is smaller than d, then a.b.c precedes d.e.f
- If a is equal to d, and b is smaller than e, then a.b.c precedes d.e.f
- If a is equal to d, and b is equal to e, and c is smaller than f, then a.b.c precedes d.e.f
- 1.0.0 precedes 2.0.0. Equivalently: 1.0.0 is smaller than 2.0.0 or 2.0.0 is greater than 1.0.0.
- 2.0.0 precedes 2.1.0. Equivalently: 2.0.0 is smaller than 2.1.0 or 2.1.0 is greater than 2.0.0.
- 2.1.0 precedes 2.1.1. Equivalently: 2.1.0 is smaller than 2.1.1 or 2.1.1 is greater than 2.1.0.
Operators
Developers can specify version constraints using the following operators:- a.b.c or =a.b.c - Requires exactly version a.b.c of the compiler
- >a.b.c - Requires the compiler version to be greater than a.b.c.
- >=a.b.c - Requires the compiler version to be greater than or equal to a.b.c
- <a.b.c - Requires the compiler version to be less than a.b.c
- <=a.b.c - Requires the compiler version to be less than or equal to a.b.c
- ^a.b.c - Requires the major part of the compiler version to be equal to the a part, the minor to be equal to the b part, and the patch to be no lower than the c part
- ^a.b - Requires the major compiler version to be equal to the a part and the minor to be no lower than the b part
- ^a - Requires the major compiler version to be no lower than the a part
- >a.b is equivalent to >a.b.0
- <=a is equivalent to <=a.0.0
- ^a.b is not equivalent to ^a.b.0
- ^a is not equivalent to ^a.0.0
- ^5.1.2 matches compiler version 5.1.3 because patch
3is no lower than patch2. - ^5.1.2 does not match compiler version 5.2.3 because minor
2does not equal minor1. - ^5.1.2 does not match compiler version 5.1.1 because patch
1is lower than patch2. - ^5.1 matches compiler version 5.1.3 because minor
1is no lower than minor1. - ^5.1 matches compiler version 5.2.3 because minor
2is no lower than minor1. - ^5.1 matches compiler version 5.1.0 because minor
1is no lower than minor1. - ^5.1 does not match compiler version 5.0.2 because minor
0is lower than minor1. - ^5 matches compiler version 5.1.0 because major
5is no lower than major5. - ^5 does not match compiler version 4.1.0 because major
4is lower than major5. - >5.1.2 matches compiler version 5.1.3 because patch
3is bigger than patch2. - >5.1.2 matches compiler version 5.2.0 because minor
2is bigger than minor1. - >5.1.2 matches compiler version 6.0.0 because major
6is bigger than major5. - =5.1.2 does not match compiler version 5.2.2 because minor
2is not equal to minor1.
The
#pragma version directive can be used multiple times, and the compiler must satisfy all specified constraints.#pragma not-version
The #pragma not-version is similar to #pragma version, but it fails if the specified condition is met.
Syntax:
<op> is an optional version operator that allows to specify a constraint, and <sem_version> is identical as
in #pragma version.
This directive is useful for blocking specific compiler versions known to have issues.
Here are some examples:
not-version >2.1.3 matches any compiler version that is not bigger than 2.1.3, like 2.1.2, 2.0.5 and even 2.1.3 itself.
In the second example, not-version ^3.4 matches any compiler version that does not match ^3.4, like 3.3.1, 4.4.0, and 3.3.9
In the third example, not-version 1.2.3 matches any compiler version different from 1.2.3.
#pragma allow-post-modification
Introduced in FunC v0.4.1
In Func, using a variable before it is modified within the same expression is prohibited by default.
For example, the following code will not compile, because ds is used before it is modified in ds~load_uint(8).
See modifying notation for more details on using symbol ~.
ds is used after it is modified:
#pragma allow-post-modification.
This allows variables to be modified after usage in mass assignments and function calls while sub-expressions are still computed left to right.
In the following example, x will contain the initial value of ds, while y the modified value of ds:
#pragma allow-post-modification works only for code after the pragma.#pragma compute-asm-ltr
Introduced in FunC v0.4.1
asm declarations can override the order of argument evaluation. For example, in the following expression:
load_ref()load_uint(256)load_dict()load_uint(8)
asm declaration:
asm(value index dict key_len) notation dictates a rearrangement of arguments.
To ensure strict left-to-right computation order of the arguments, use #pragma compute-asm-ltr.
With this directive enabled, the same function call:
load_dict()load_uint(8)load_uint(256)load_ref()
asm rearrangement will occur.
#pragma compute-asm-ltr works only for code after the pragma.