From b1998d3b98d5b71a898d7ad5aee045be496c911a Mon Sep 17 00:00:00 2001 From: Tim McMackin Date: Thu, 30 Jan 2025 16:15:30 -0500 Subject: [PATCH 1/2] Combined preprocessor topic --- gitlab-pages/docs/compiling/preprocessor.md | 416 ++++++++++++++++++ .../compiling/src/preprocessor/euro.jsligo | 6 + .../compiling/src/preprocessor/euro.mligo | 6 + .../preprocessor/euro_namespace_public.jsligo | 9 + .../preprocessor/import_euro_public.jsligo | 6 + .../src/preprocessor/includereset.jsligo | 12 + .../src/preprocessor/includereset.mligo | 12 + .../src/preprocessor/main_importer.jsligo | 6 + .../src/preprocessor/main_importer.mligo | 5 + .../src/preprocessor/ungrouped.mligo | 14 + .../docs/reference/decorators/public.md | 2 +- gitlab-pages/docs/syntax/modules.md | 4 +- gitlab-pages/website/sidebars.js | 1 + 13 files changed, 496 insertions(+), 3 deletions(-) create mode 100644 gitlab-pages/docs/compiling/preprocessor.md create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/euro.mligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/import_euro_public.jsligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/includereset.jsligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/includereset.mligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/main_importer.jsligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/main_importer.mligo create mode 100644 gitlab-pages/docs/compiling/src/preprocessor/ungrouped.mligo diff --git a/gitlab-pages/docs/compiling/preprocessor.md b/gitlab-pages/docs/compiling/preprocessor.md new file mode 100644 index 0000000000..f1902f5732 --- /dev/null +++ b/gitlab-pages/docs/compiling/preprocessor.md @@ -0,0 +1,416 @@ +--- +id: preprocessor +title: Preprocessor +--- + +import Syntax from '@theme/Syntax'; + +The preprocessor edits files before they go to the LIGO compiler. +You can include commands called _preprocessor directives_ to instruct the preprocessor to make changes to a file before the compiler receives it, such as including or excluding code and importing code from other files. + +Preprocessor directives can allow you to make changes to files before the compiler processes them. +For example, the following contract has three entrypoints, but one is between `#if` and `#endif` directives. +The line `#if INCLUDE_RESET` instructs the preprocessor to include the text between the directives (in this case, the third entrypoint) only if the `INCLUDE_RESET` Boolean variable is set: + + + +```cameligo group=includereset +module MyContract = struct + type storage = int + type result = operation list * storage + + [@entry] let increment (delta : int) (storage : storage) : result = [],storage + delta + + [@entry] let decrement (delta : int) (storage : storage) : result = [],storage - delta + + #if INCLUDE_RESET + [@entry] let reset () (_storage : storage) : result = [], 0 + #endif +end +``` + + + + + +```jsligo group=includereset +export namespace MyContract { + export type storage = int; + export type result = [list, storage]; + + @entry const increment = (delta : int, storage : storage) : result => [[], storage + delta]; + + @entry const decrement = (delta : int, storage : storage) : result => [[], storage - delta]; + + #if INCLUDE_RESET + @entry const reset = (_u : unit, _storage : storage) : result => [[], 0]; + #endif +} +``` + + + + + +You can set these Boolean preprocessor variables with the [`#define`](#define-and-undef) directive or by passing them to the `-D` argument of the `ligo compile contract` command. +For example, if the contract in the previous example is in a file named `mycontract.mligo`, this command causes the preprocessor and compiler to output a contract with only two entrypoints: + +```bash +ligo compile contract mycontract.mligo +``` + +This command passes the `INCLUDE_RESET` Boolean variable to the preprocessor and causes the compiler to output a contract with three entrypoints: + +```bash +ligo compile contract -D INCLUDE_RESET mycontract.mligo +``` + + + + + +You can set these Boolean preprocessor variables with the [`#define`](#define-and-undef) directive or by passing them to the `-D` argument of the `ligo compile contract` command. +For example, if the contract in the previous example is in a file named `mycontract.jsligo`, this command causes the preprocessor and compiler to output a contract with only two entrypoints: + +```bash +ligo compile contract mycontract.jsligo +``` + +This command passes the `INCLUDE_RESET` Boolean variable to the preprocessor and causes the compiler to output a contract with three entrypoints: + +```bash +ligo compile contract -D INCLUDE_RESET mycontract.jsligo +``` + + + +## Viewing the preprocessor output + +It's rarely necessary to view the output of the preprocessor, but if you need to see the output to debug directives, you can view the output with the `ligo print preprocessed` command, as in this example: + + + +```bash +ligo print preprocessed myContract.mligo +``` + + + + + +```bash +ligo print preprocessed myContract.jsligo +``` + + + +## Comments + +The preprocessor ignores directives that are in [comments](../syntax/comments), which prevents problems where comments in your code contain text that looks like a directive. +For example, this code is valid because the preprocessor ignores the text `#endif` in the comment: + +``` +#if true + // #endif +#endif +``` + +The preprocessor includes and excludes comments just like any other line of code. + +## String processing + +The preprocessor ignores directives that are in strings, which prevents problems where strings in your code contain text that looks like a directive. + +For example, this code includes a string with the text `#endif`, but the preprocessor does not interpret this text as the `#endif` directive: + + + +```cameligo skip +#if true +let textValue = "This string includes the text #endif" +#endif +``` + + + + + +```jsligo skip +#if true +const textValue = "This string includes the text #endif"; +#endif +``` + + + +## Blank lines + +When the preprocessor hides text, it includes a blank line consisting only of a newline character in place of the omitted line to keep line numbers in compiler errors consistent with the source file. +Similarly, it includes a blank line in place of each preprocessor directive. +These blank lines do not affect compilation. + +For example, take this source file: + +``` +#if false +This is NOT copied to the output, except the newline character +#endif +``` + +The output that goes to the compiler from this source file is three blank lines plus the linemarker that indicates the start of the file: + +``` +# 1 "mySourceFile.txt" + + + +``` + +## Linemarkers + +As in C-based languages, the LIGO preprocessor includes [linemarkers](https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html) in files that it processes. +For example, if you include files with the `#include` directive, the preprocessor inserts a line in the processed file to indicate where the included file starts and a line to indicate where the included file ends and the original file resumes. + +The output begins with a linemarker that indicates the start of the original file that was sent to the preprocessor, in the format `# ""`. +Other linemarkers follow the same format, adding the number `1` to indicate the start of an imported file and the number `2` to indicate the end of the imported file and the resumption of the previous file. + +The following example uses three files: `a.txt`, `b.txt`, and `c.txt`. +File A includes file B and file B includes file C. + +``` +Start of "a.txt" +#include "b.txt" +End of "a.txt" +``` + +``` +Start of "b.txt" +#include "c.txt" +End of "b.txt" +``` + +``` +Start of "c.txt" +End of "c.txt" +``` + +If you create these files and run the command `ligo print preprocessed --syntax cameligo a.txt`, the output includes linemarkers that indicate where the files begin and end and the line number in the file that the preprocessor is on at the time: + +``` +# 1 "a.txt" +Start of "a.txt" + +# 1 "b.txt" 1 +Start of "b.txt" + +# 1 "c.txt" 1 +Start of "c.txt" +End of "c.txt" +# 3 "b.txt" 2 +End of "b.txt" +# 3 "a.txt" 2 +End of "a.txt" +``` + +The LIGO compiler ignores these linemarkers when it compiles the code. + +## Directives + +These are the preprocessor directives that the LIGO preprocessor supports: + +- [`#define` and `#undef`](#define-and-undef) +- [`#error`](#error) +- [`#if`, `#else`, `#elif`, and `#endif`](#if-else-elif-and-endif) +- [`#import`](#import) +- [`#include`](#include) + +### `#define` and `#undef` + +The `#define` directive sets a Boolean variable (also known as a _symbol_) to true, and the `#undef` directive unsets it, which is equivalent to setting it to false. + +You can use these variables with the `#if` directive to show or hide text from the compiler, as in this example: + +``` +#define SYM + +#if SYM +This IS copied to the output because SYM is set. +#else +This is NOT copied to the output, except the newline character. +#endif +``` + +### `#error` + +The `#error` directive forces the preprocessor to stop and emit an error. +This directive can help you catch problems in complex files. +You can include an error message, as in this example: + +``` +#error Not implemented/tested yet +``` + +### `#if`, `#else`, `#elif`, and `#endif` + +These conditional directives allow you to include or exclude text conditionally. +They use a syntax similar to conditions in many other languages, starting with `#if` and ending with `#endif`. +Logic between these two directives can also include: + +- One `#else` directive before `#endif` + +- One or more `#elif` directives as a shorthand for a + `#else` immediately followed by an `#if` + +For example: + +``` +#if CONDITION_A +CONDITION_A is true +#elif CONDITION_B +CONDITION_B is true +#else +Neither A nor B are true +#endif +``` + +The `#if` and `#elif` directives support basic Boolean logic, including: + +- `||` for the disjunction ("or") +- `&&` for the conjunction ("and") +- `==` for equality +- `!=` for inequality +- `!` for negation +- `(` and `)` around expressions to specify order of operations + +For real-world examples of this logic, see [Dexter](https://gitlab.com/dexter2tz/dexter2tz/-/blob/febd360cf6df6e090dedbf21b27538681246f980/dexter.mligo#L52). +In one section, it uses different record types depending on the version of the FA standard in use (see [`dexter.mligo` line 84](https://gitlab.com/dexter2tz/dexter2tz/-/blob/febd360cf6df6e090dedbf21b27538681246f980/dexter.mligo#L84)): + +```cameligo +type storage = + [@layout:comb] + { tokenPool : nat ; + xtzPool : tez ; + lqtTotal : nat ; + selfIsUpdatingTokenPool : bool ; + freezeBaker : bool ; + manager : address ; + tokenAddress : address ; +#if FA2 + tokenId : nat ; +#endif + lqtAddress : address ; + } +``` + +### `#import` + + + +The `#import` directive prompts the preprocessor to include another file as a [module](../syntax/modules) in the current file. + +For example, you can create a file with related type definitions, as in this example file named `euro.mligo`: + +```cameligo group=euro +type t = nat + +let add (a, b : t * t) : t = a + b + +let one : t = 1n +let two : t = 2n +``` + +In another file, you can import this file, assign it the module `Euro`, and use its definitions: + +```cameligo group=main_importer +#import "gitlab-pages/docs/compiling/src/preprocessor/euro.mligo" "Euro" + +type storage = Euro.t + +let tip (s : storage) : storage = Euro.add (s, Euro.one) +``` + +For more information, see [Modules](../syntax/modules). + + + + + +The `#import` directive prompts the preprocessor to include another file as a [namespace](../syntax/modules) in the current file. + +For example, you can create a file with related type definitions, as in this example file named `euro.jsligo`: + +```jsligo group=euro +export type t = nat; + +export const add = (a: t, b: t): t => a + b; + +export const one: t = 1n; +export const two: t = 2n; +``` + +In another file, you can import this file, assign it the namespace `Euro`, and use its definitions: + +```jsligo group=main_importer +#import "gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo" "Euro" + +type storage = Euro.t; + +const tip = (s : storage) : storage => + Euro.add (s, Euro.one); +``` + +When you import a file with the `#import` directive, LIGO packages the file as a namespace. +Therefore, any namespaces in the file are sub-namespaces of that namespace. + +However, the namespace does not export those sub-namespaces automatically. +As a result, if you import a file that contains namespaces, those namespaces are not accessible. + +To work around this limitation, add the `@public` decorator to the namespaces in the file. +For example, this file defines the Euro type as a namespace with the `@public` decorator: + +```jsligo group=euro_namespace_public +// This file is gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo + +@public +namespace Euro { + export type t = nat; + export const add = (a: t, b: t) : t => a + b; + export const one: t = 1n; + export const two: t = 2n; +}; +``` + +Because the namespace is public, you can access it as a sub-namespace when you import the file into another file: + +```jsligo group=import_euro_public +#import "gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo" "Euro_import" + +type euro_balance = Euro_import.Euro.t; + +const add_tip = (s: euro_balance): euro_balance => + Euro_import.Euro.add(s, Euro_import.Euro.one); +``` + +For more information, see [Namespaces](../syntax/modules). + + + +### `#include` + +The `#include` directive includes the entire text contents of the specified file, as in this example: + +``` +#include "path/to/standard_1.ligo" +``` + + + +Unlike the `#import` directive, the `#include` directive does not package the included file as a module. + + + + + +Unlike the `#import` directive, the `#include` directive does not package the included file as a namespace. + + diff --git a/gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo b/gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo new file mode 100644 index 0000000000..6148acf659 --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo @@ -0,0 +1,6 @@ +export type t = nat; + +export const add = (a: t, b: t): t => a + b; + +export const one: t = 1n; +export const two: t = 2n; \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/euro.mligo b/gitlab-pages/docs/compiling/src/preprocessor/euro.mligo new file mode 100644 index 0000000000..361443ca2c --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/euro.mligo @@ -0,0 +1,6 @@ +type t = nat + +let add (a, b : t * t) : t = a + b + +let one : t = 1n +let two : t = 2n \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo b/gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo new file mode 100644 index 0000000000..130b17ac90 --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo @@ -0,0 +1,9 @@ +// This file is gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo + +@public +namespace Euro { + export type t = nat; + export const add = (a: t, b: t) : t => a + b; + export const one: t = 1n; + export const two: t = 2n; +}; \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/import_euro_public.jsligo b/gitlab-pages/docs/compiling/src/preprocessor/import_euro_public.jsligo new file mode 100644 index 0000000000..804498fb5c --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/import_euro_public.jsligo @@ -0,0 +1,6 @@ +#import "gitlab-pages/docs/compiling/src/preprocessor/euro_namespace_public.jsligo" "Euro_import" + +type euro_balance = Euro_import.Euro.t; + +const add_tip = (s: euro_balance): euro_balance => + Euro_import.Euro.add(s, Euro_import.Euro.one); \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/includereset.jsligo b/gitlab-pages/docs/compiling/src/preprocessor/includereset.jsligo new file mode 100644 index 0000000000..a138e4a61f --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/includereset.jsligo @@ -0,0 +1,12 @@ +export namespace MyContract { + export type storage = int; + export type result = [list, storage]; + + @entry const increment = (delta : int, storage : storage) : result => [[], storage + delta]; + + @entry const decrement = (delta : int, storage : storage) : result => [[], storage - delta]; + + #if INCLUDE_RESET + @entry const reset = (_u : unit, _storage : storage) : result => [[], 0]; + #endif +} \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/includereset.mligo b/gitlab-pages/docs/compiling/src/preprocessor/includereset.mligo new file mode 100644 index 0000000000..86602241f7 --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/includereset.mligo @@ -0,0 +1,12 @@ +module MyContract = struct + type storage = int + type result = operation list * storage + + [@entry] let increment (delta : int) (storage : storage) : result = [],storage + delta + + [@entry] let decrement (delta : int) (storage : storage) : result = [],storage - delta + + #if INCLUDE_RESET + [@entry] let reset () (_storage : storage) : result = [], 0 + #endif +end \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/main_importer.jsligo b/gitlab-pages/docs/compiling/src/preprocessor/main_importer.jsligo new file mode 100644 index 0000000000..8c98a89566 --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/main_importer.jsligo @@ -0,0 +1,6 @@ +#import "gitlab-pages/docs/compiling/src/preprocessor/euro.jsligo" "Euro" + +type storage = Euro.t; + +const tip = (s : storage) : storage => + Euro.add (s, Euro.one); \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/main_importer.mligo b/gitlab-pages/docs/compiling/src/preprocessor/main_importer.mligo new file mode 100644 index 0000000000..6e9c14a81f --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/main_importer.mligo @@ -0,0 +1,5 @@ +#import "gitlab-pages/docs/compiling/src/preprocessor/euro.mligo" "Euro" + +type storage = Euro.t + +let tip (s : storage) : storage = Euro.add (s, Euro.one) \ No newline at end of file diff --git a/gitlab-pages/docs/compiling/src/preprocessor/ungrouped.mligo b/gitlab-pages/docs/compiling/src/preprocessor/ungrouped.mligo new file mode 100644 index 0000000000..a13778d743 --- /dev/null +++ b/gitlab-pages/docs/compiling/src/preprocessor/ungrouped.mligo @@ -0,0 +1,14 @@ +type storage = + [@layout:comb] + { tokenPool : nat ; + xtzPool : tez ; + lqtTotal : nat ; + selfIsUpdatingTokenPool : bool ; + freezeBaker : bool ; + manager : address ; + tokenAddress : address ; +#if FA2 + tokenId : nat ; +#endif + lqtAddress : address ; + } \ No newline at end of file diff --git a/gitlab-pages/docs/reference/decorators/public.md b/gitlab-pages/docs/reference/decorators/public.md index d11e592a69..7f2fa9335a 100644 --- a/gitlab-pages/docs/reference/decorators/public.md +++ b/gitlab-pages/docs/reference/decorators/public.md @@ -15,6 +15,6 @@ Because code is public by default in CameLIGO, this attribute is not needed in t The decorator `@public` labels a declaration as available to be called by other pieces of code, similar to the `export` keyword. -This decorator is needed only when you want to make a namespace available to code in other files, as described in [Importing namespaces](../../preprocessor/import#importing-namespaces). +This decorator is needed only when you want to make a namespace available to code in other files, as described in [`#import](../../compiling/preprocessor/#import). diff --git a/gitlab-pages/docs/syntax/modules.md b/gitlab-pages/docs/syntax/modules.md index 7beca33ab2..fe9d6d56dd 100644 --- a/gitlab-pages/docs/syntax/modules.md +++ b/gitlab-pages/docs/syntax/modules.md @@ -315,13 +315,13 @@ Including modules is not possible in JsLIGO. ## Importing modules You can import modules from other files with the `#import` directive. -See [`#import`](../preprocessor/import). +See [`#import`](../compiling/preprocessor#import). You can import namespaces from other files with the `#import` directive, but only if the namespaces have the `@public` decorator. -See [`#import`](../preprocessor/import). +See [`#import`](../compiling/preprocessor#import). diff --git a/gitlab-pages/website/sidebars.js b/gitlab-pages/website/sidebars.js index 5a803dfff8..2526e69fad 100644 --- a/gitlab-pages/website/sidebars.js +++ b/gitlab-pages/website/sidebars.js @@ -142,6 +142,7 @@ const sidebars = { "testing/michelson_testing" ], "Compiling": [ + "compiling/preprocessor", "compiling/compiling", "compiling/deploying" ], From 7dcbfd3545c6edd66b9667f91a70c5c5f047ec79 Mon Sep 17 00:00:00 2001 From: Tim McMackin Date: Fri, 31 Jan 2025 11:35:09 -0500 Subject: [PATCH 2/2] Remove preprocessor section --- gitlab-pages/docs/preprocessor/comments.md | 43 ------- gitlab-pages/docs/preprocessor/define.md | 95 -------------- gitlab-pages/docs/preprocessor/error.md | 16 --- gitlab-pages/docs/preprocessor/if.md | 82 ------------ gitlab-pages/docs/preprocessor/import.md | 121 ------------------ gitlab-pages/docs/preprocessor/include.md | 110 ---------------- .../docs/preprocessor/preprocessor.md | 48 ------- .../docs/preprocessor/src/import/euro.jsligo | 6 - .../docs/preprocessor/src/import/euro.mligo | 6 - .../src/import/euro_namespace_public.jsligo | 9 -- .../src/import/import_euro_public.jsligo | 6 - .../src/import/main_importer.jsligo | 6 - .../src/import/main_importer.mligo | 5 - gitlab-pages/docs/preprocessor/strings.md | 30 ----- gitlab-pages/website/sidebars.js | 10 -- 15 files changed, 593 deletions(-) delete mode 100644 gitlab-pages/docs/preprocessor/comments.md delete mode 100644 gitlab-pages/docs/preprocessor/define.md delete mode 100644 gitlab-pages/docs/preprocessor/error.md delete mode 100644 gitlab-pages/docs/preprocessor/if.md delete mode 100644 gitlab-pages/docs/preprocessor/import.md delete mode 100644 gitlab-pages/docs/preprocessor/include.md delete mode 100644 gitlab-pages/docs/preprocessor/preprocessor.md delete mode 100644 gitlab-pages/docs/preprocessor/src/import/euro.jsligo delete mode 100644 gitlab-pages/docs/preprocessor/src/import/euro.mligo delete mode 100644 gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo delete mode 100644 gitlab-pages/docs/preprocessor/src/import/import_euro_public.jsligo delete mode 100644 gitlab-pages/docs/preprocessor/src/import/main_importer.jsligo delete mode 100644 gitlab-pages/docs/preprocessor/src/import/main_importer.mligo delete mode 100644 gitlab-pages/docs/preprocessor/strings.md diff --git a/gitlab-pages/docs/preprocessor/comments.md b/gitlab-pages/docs/preprocessor/comments.md deleted file mode 100644 index 4f9c15f6b5..0000000000 --- a/gitlab-pages/docs/preprocessor/comments.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -id: comments -title: Comments ---- - -import Syntax from '@theme/Syntax'; - -Comments are recognised by the preprocessor, even in pieces of the -input that are not copied. (This last point is a difference between -`cpp` and the `C#` preprocessor.) The rationale for doing so when -copying the input is that we do not want the preprocessor to interpret -a directive that is actually in a comment. This can happen when -commenting out a piece of the source code that contains a -preprocessing directive: we do not want that directive to be -interpreted. - -When the processor is in skip mode, that is, the input is not copied, -comments are also recognised. This ensures that a comment containing a -conditional directive, for example `#endif`, does not start to -interact with previous directives, like `#if`, or raises an error when -switching from copy mode to skip mode. In other words, the -interpretation of comments should always be the same. For -example, we want the following input to be valid: - -``` -#if true - // #endif -#endif -``` - - - -Comments are blocks enclosed between `(*` and `*)`, and start with -`//` for line comments. - - - - - -Comments are blocks enclosed between `/*` and `*/`, and start with -`//` for line comments. - - diff --git a/gitlab-pages/docs/preprocessor/define.md b/gitlab-pages/docs/preprocessor/define.md deleted file mode 100644 index 6f11de0499..0000000000 --- a/gitlab-pages/docs/preprocessor/define.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -id: define -title: "#define" ---- - -import Syntax from '@theme/Syntax'; - -The booleans `false` and `true` are predefined. The way to define -_symbols_ (that is the traditional name of those identifiers) consists -in using the `#define` directive, followed by the symbol, like so: - -``` -#define SYM - -#if SYM -This IS copied to the output. -#else -This is NOT copied to the output, except the newline character. -#endif -``` - -This opens the possibility to use Boolean expressions made of - -- `true` and `false` already mentioned; -- `||` for the disjunction ("or"); -- `&&` for the conjunction ("and"); -- `==` for equality; -- `!=` for inequality; -- `!` for negation; -- `(` and `)` around expressions to specify priorities. - -Directives are processed in sequence in the input file. This -preprocessor, like that of `C#`, allows us to _undefine_ a symbol, -that is, giving it the Boolean value `false`, like so: - -``` -#define SYM -#undef SYM - -#if SYM -This is NOT copied to the output, except the newline character. -#else -This IS copied to the output. -#endif -``` - -The result is - -``` -# 1 "Tests/undef.txt" - - - - - - -This IS copied to the output. - -``` - -Note: If you wish to redefine a symbol, you must undefine it first. - -When we want to write a cascade of conditionals, the preprocessor -enables a shortcut by means of the `#elif` directive, like so: - -``` -#if ... -... -#elif ... -... -#elif ... -... -#endif -``` - -Basically, a `#elif` directive is equivalent to `#else` followed by -`#if`, but we only need to close with only one `#endif`. - -The rationale for using conditional directives in LIGO is to enable in -a single smart contract several versions of a standard. - -``` -#if STANDARD_1 -... -#elif STANDARD_2 -... -#else -#error Standard not implemented -#endif -``` - -A real life example could be -[Dexter](https://gitlab.com/dexter2tz/dexter2tz/-/blob/febd360cf6df6e090dedbf21b27538681246f980/dexter.mligo#L52). It -provides another interesting use of a conditional directive, where -[a record type depends on the version of the standard](https://gitlab.com/dexter2tz/dexter2tz/-/blob/febd360cf6df6e090dedbf21b27538681246f980/dexter.mligo#L84). diff --git a/gitlab-pages/docs/preprocessor/error.md b/gitlab-pages/docs/preprocessor/error.md deleted file mode 100644 index 2cfaee654e..0000000000 --- a/gitlab-pages/docs/preprocessor/error.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -id: error -title: "#error" ---- - -import Syntax from '@theme/Syntax'; - -When debugging or putting in place directives in an already existing -input, it is sometimes useful to force the preprocessor to stop and -emit an error. This is possible thanks to the `#error` directive, -which is followed by an error message as free text until the end of -the line, like so: - -``` -#error Not implemented/tested yet -``` diff --git a/gitlab-pages/docs/preprocessor/if.md b/gitlab-pages/docs/preprocessor/if.md deleted file mode 100644 index e8d5b0c248..0000000000 --- a/gitlab-pages/docs/preprocessor/if.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -id: if -title: "#if" ---- - -import Syntax from '@theme/Syntax'; - -The preprocessor enables the conditional copying of its input. At the -start, its default mode is _copy_, meaning that characters in the -input are copied to the output. Conditional directives enable another -mode: _skip_, by means of which the following characters are -discarded, and only newline characters are copied. - -Conditional directives follow the familiar syntax of some of their -cousins in programming languages. At the very least, - -1. they start with the `#if` directive, followed by a Boolean - expression as argument, - -2. and they are closed by `#endif`. - -It is also possible to use - -- one `#else` directive before `#endif`; - -- a series of `#elif` directive after `#if` (as a short-hand for a - `#else` immediately followed by an `#if`, except that only one - `#endif` will close the conditional). - -A trivial example would be: - -``` -#if false -This is NOT copied to the output, except the newline character -#endif -``` - -where `false` is a predefined symbol acting like a Boolean value. The -output is - -``` -# 1 "Tests/test.txt" - - - - -``` - -Note what looks like an anonymous preprocessing directive `# 1 "Tests/test.txt"`. We will explain its meaning when presenting -[The Inclusion Directive](#the-inclusion-directive). (Remark: `cpp` -would not output blank lines followed by the end of the file.) Their -use is clearer if we add text before and after the conditional, like -so: - -``` ---- -#if false -A -#endif ---- -``` - -whose preprocessed output is then - -``` -# 1 "Tests/test.txt" ---- - - - ---- -``` - -Here is how to use the `#else` directive: - -``` -#if false -This is NOT copied to the output, except the newline character. -#else -This IS copied to the output. -#endif -``` diff --git a/gitlab-pages/docs/preprocessor/import.md b/gitlab-pages/docs/preprocessor/import.md deleted file mode 100644 index ec0ae6c97c..0000000000 --- a/gitlab-pages/docs/preprocessor/import.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -id: import -title: "#import" ---- - -import Syntax from '@theme/Syntax'; - -The `#import` directive is specific to the LIGO compiler. It provides -the support for a minimal module/namespace system. - - - -For more information about modules, see [Modules](../syntax/modules). - -Modules get more handy when they can be made from a file, separate -from our own program, like a library: when we *import* a module from -such a file, we automatically obtain a module encapsulating all the -definitions in it. This will become very handy for organising large -contracts, as we can divide it into different files, and the module -system keeps the naming space clean (no need for name mangling). - -Generally, we will take a set of definitions that can be naturally -grouped by functionality, and put them together in a separate -file. For example, we can create a file `euro.mligo`: - -```cameligo group=euro -type t = nat - -let add (a, b : t * t) : t = a + b - -let one : t = 1n -let two : t = 2n -``` - -In another file, we can import `euro.mligo` as a module, and use its -definitions. For example, we can create a `main.mligo` that imports -all definitions from `euro.mligo` as the module `Euro`: - -```cameligo group=main_importer -#import "gitlab-pages/docs/preprocessor/src/import/euro.mligo" "Euro" - -type storage = Euro.t - -let tip (s : storage) : storage = Euro.add (s, Euro.one) -``` - - - - - -For more information about namespaces, see [Namespaces](../syntax/modules). - -Namespaces get more handy when they can be made from a file, separate -from our own program, like a library: when we *import* a namespace -from such a file, we automatically obtain a namespace encapsulating -all the definitions in it. This will become very handy for organising -large contracts, as we can divide it into different files, and the -namespace system keeps the naming space clean (no need for name -mangling). - -Generally, we will take a set of definitions that can be naturally -grouped by functionality, and put them together in a separate -file. For example, we can create a file `euro.jsligo`: - -```jsligo group=euro -export type t = nat; - -export const add = (a: t, b: t): t => a + b; - -export const one: t = 1n; -export const two: t = 2n; -``` - -In another file, we can import `euro.jsligo` as a namespace, and use -its definitions. For example, we can create a `main.jsligo` that -imports all definitions from `euro.jsligo` as the namespace `Euro`: - -```jsligo group=main_importer -#import "gitlab-pages/docs/preprocessor/src/import/euro.jsligo" "Euro" - -type storage = Euro.t; - -const tip = (s : storage) : storage => - Euro.add (s, Euro.one); -``` - -## Importing namespaces - -When you import a file with the `#import` directive, LIGO packages the file as a namespace. -Therefore, any namespaces in the file are sub-namespaces of that namespace. - -However, the namespace does not export those sub-namespaces automatically. -As a result, if you import a file that contains namespaces, those namespaces are not accessible. - -To work around this limitation, add the `@public` decorator to the namespaces in the file. -For example, this file defines the Euro type as a namespace with the `@public` decorator: - -```jsligo group=euro_namespace_public -// This file is gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo - -@public -namespace Euro { - export type t = nat; - export const add = (a: t, b: t) : t => a + b; - export const one: t = 1n; - export const two: t = 2n; -}; -``` - -Because the namespace is public, you can access it as a sub-namespace when you import the file into another file: - -```jsligo group=import_euro_public -#import "gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo" "Euro_import" - -type euro_balance = Euro_import.Euro.t; - -const add_tip = (s: euro_balance): euro_balance => - Euro_import.Euro.add(s, Euro_import.Euro.one); -``` - - diff --git a/gitlab-pages/docs/preprocessor/include.md b/gitlab-pages/docs/preprocessor/include.md deleted file mode 100644 index c22bcdf3df..0000000000 --- a/gitlab-pages/docs/preprocessor/include.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -id: include -title: "#include" ---- - -import Syntax from '@theme/Syntax'; - -The solution provided by the conditional directives with symbol -definition to manage several standards is improved upon by physically -separating the input into different files. This is where the -`#include` directive comes handy. Basically, it takes an argument made -of a string containing a path to the file to be textually included, -like so: - -``` -#include "path/to/standard_1.ligo" -``` - -and the preprocessor replaces the directive with the contents of the -file `path/to/standard_1.ligo`, whose contents is then preprocessed as -well. This can in theory create a loop, for example, if two files try -to include each other. - -In fact, the preprocessor does more than simply include the given -file. To enable the consumer of the output to keep track of -inclusions, in particular, to maintain the line numbers of the input -that has been copied, the preprocessor inserts two special directives -in the output, called -[linemarkers](https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html), -one in the stead of the `#include` directive and one after the -inclusion. Let us consider the following example where `a.txt` -includes `b.txt`, which, in turn, includes `c.txt`. Here is the -contents of `a.txt`: - -``` -Start of "a.txt" -#include "b.txt" -End of "a.txt" -``` - -Then `b.txt`: - -``` -Start of "b.txt" -#include "c.txt" -End of "b.txt" -``` - -and, finally, `c.txt`: - -``` -Start of "c.txt" -End of "c.txt" -``` - -If we gather the files in a `Tests` directory and run the preprocessor -only, like so - -> $ ligo print preprocessed Tests/a.txt - -we obtain on `stdout`: - -``` -# 1 "Tests/a.txt" -Start of "a.txt" - -# 1 "Tests/b.txt" 1 -Start of "b.txt" - -# 1 "Tests/c.txt" 1 -Start of "c.txt" -End of "c.txt" -# 3 "Tests/b.txt" 2 -End of "b.txt" -# 3 "Tests/a.txt" 2 -End of "a.txt" -``` - -There are three forms of linemarkers: - -1. `# "path/to/file"` -2. `# "path/to/file" 1` -3. `# "path/to/file" 2` - -The first kind is used only at the start of the output file and states -that the line after the linemarker has number `` and -belongs to the file `path/to/file`. Therefore `Start of "a.txt"` has -line number `1` in file `Tests/a.txt`. - -The second kind is used when including a file. The `#include` -directive is discarded in the output, except the newline character, -which explains the empty line after `Start of "a.txt"`. Then a -linemarker ending in `1` is printed, which means that we went to the -file `path/to/file` when processing the input. - -The third kind is inserted in the output upon returning from an -included file. For example, `# 3 "Tests/b.txt" 2` means that the next -line has number `3` and we return to file `Tests/b.txt`. - -Linemarkers need to be handled by the consumer of the output. In the -context of the LIGO compiler, the lexer reads the output of the -preprocessor, therefore scans for linemarkers. - -When using the preprocessor with the LIGO compiler, the `#include` -directive can only occur at the top level according to the grammar, -that is, either at the beginning of the smart contract, in between -file-level declarations or at the end. (This property is checked by -the parser.) The rationale for this restriction is to avoid fragments -of smart contracts that are syntactically incorrect, and yet assembled -into a correct one. diff --git a/gitlab-pages/docs/preprocessor/preprocessor.md b/gitlab-pages/docs/preprocessor/preprocessor.md deleted file mode 100644 index f6a727ef4a..0000000000 --- a/gitlab-pages/docs/preprocessor/preprocessor.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -id: preprocessor -title: Preprocessor ---- - -import Syntax from '@theme/Syntax'; - -A preprocessor is a tool that reads a text file and, if some special -instructions, called _preprocessing directives_, are found in the -input, the output may not be an identical copy, for example some parts -can be skipped. We document here the preprocessor shipped with the -LIGO compiler. - -This preprocessor features different kinds of directives: - -- directives found in the standard preprocessor for the language - `C#`; - -- a directive from `cpp`, the `C` preprocessor, enabling the textual - inclusion of files; - -- a directive specific to LIGO to support a minimal module system. - -Importantly, strings and comments are handled the way `cpp` does --- -not `C#`. - -In the following subsections, we shall briefly present those -directives. Here, we state some properties which hold for all of -them. - -- They must start with a `#` symbol at the beginning of a line. - -- Wrongly spelled directives or unsupported ones are ignored without - warning, and therefore will appear in the output. - -- They can have arguments in the form of free text or - strings. (Anything after the directive name is considered a - potential argument.) - -- String arguments must be enclosed between double quotes and - cannot span over two or more lines. - -- The valid preprocessing of a directive leaves in its place an - empty line (that is, a newline character) or another directive, to - be picked up by other tools, like lexers. - -- Newline characters are never discarded, to preserve the line - numbers of copied text. diff --git a/gitlab-pages/docs/preprocessor/src/import/euro.jsligo b/gitlab-pages/docs/preprocessor/src/import/euro.jsligo deleted file mode 100644 index 6148acf659..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/euro.jsligo +++ /dev/null @@ -1,6 +0,0 @@ -export type t = nat; - -export const add = (a: t, b: t): t => a + b; - -export const one: t = 1n; -export const two: t = 2n; \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/src/import/euro.mligo b/gitlab-pages/docs/preprocessor/src/import/euro.mligo deleted file mode 100644 index 361443ca2c..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/euro.mligo +++ /dev/null @@ -1,6 +0,0 @@ -type t = nat - -let add (a, b : t * t) : t = a + b - -let one : t = 1n -let two : t = 2n \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo b/gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo deleted file mode 100644 index 130b17ac90..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo +++ /dev/null @@ -1,9 +0,0 @@ -// This file is gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo - -@public -namespace Euro { - export type t = nat; - export const add = (a: t, b: t) : t => a + b; - export const one: t = 1n; - export const two: t = 2n; -}; \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/src/import/import_euro_public.jsligo b/gitlab-pages/docs/preprocessor/src/import/import_euro_public.jsligo deleted file mode 100644 index b888e4bc80..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/import_euro_public.jsligo +++ /dev/null @@ -1,6 +0,0 @@ -#import "gitlab-pages/docs/preprocessor/src/import/euro_namespace_public.jsligo" "Euro_import" - -type euro_balance = Euro_import.Euro.t; - -const add_tip = (s: euro_balance): euro_balance => - Euro_import.Euro.add(s, Euro_import.Euro.one); \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/src/import/main_importer.jsligo b/gitlab-pages/docs/preprocessor/src/import/main_importer.jsligo deleted file mode 100644 index 40828f1969..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/main_importer.jsligo +++ /dev/null @@ -1,6 +0,0 @@ -#import "gitlab-pages/docs/preprocessor/src/import/euro.jsligo" "Euro" - -type storage = Euro.t; - -const tip = (s : storage) : storage => - Euro.add (s, Euro.one); \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/src/import/main_importer.mligo b/gitlab-pages/docs/preprocessor/src/import/main_importer.mligo deleted file mode 100644 index 3c806f455a..0000000000 --- a/gitlab-pages/docs/preprocessor/src/import/main_importer.mligo +++ /dev/null @@ -1,5 +0,0 @@ -#import "gitlab-pages/docs/preprocessor/src/import/euro.mligo" "Euro" - -type storage = Euro.t - -let tip (s : storage) : storage = Euro.add (s, Euro.one) \ No newline at end of file diff --git a/gitlab-pages/docs/preprocessor/strings.md b/gitlab-pages/docs/preprocessor/strings.md deleted file mode 100644 index 4016e9ec78..0000000000 --- a/gitlab-pages/docs/preprocessor/strings.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -id: strings -title: Strings ---- - -import Syntax from '@theme/Syntax'; - -Strings are recognised by the preprocessor, even in pieces of the -input that are not copied. (This last point is a difference between -`cpp` and the `C#` preprocessor.) The rationale for doing so when -copying the input is that we do not want the preprocessor to interpret -a directive that is actually in a string. This can happen if the -source code is that of a bootstrapped compiler, that is, a compiler -for its own language. Another scenario is that of a test: the source -code is actually printing what is happening. - -When the processor is in skip mode, that is, the input is not copied, -strings are also recognised. This ensures that a string containing a -conditional directive, for example `#endif`, does not start to -interact with previous directives, like `#if`, or raises an error when -switching from copy mode to skip mode. In other words, the -interpretation of strings should always be the same. For example, we -want the following input to be valid: - - -``` -#if true -"#endif" -#endif -``` diff --git a/gitlab-pages/website/sidebars.js b/gitlab-pages/website/sidebars.js index 2526e69fad..1bc4df26ba 100644 --- a/gitlab-pages/website/sidebars.js +++ b/gitlab-pages/website/sidebars.js @@ -125,16 +125,6 @@ const sidebars = { }, "data-types/parametric_types" ], - "Preprocessor": [ - "preprocessor/preprocessor", - "preprocessor/comments", - "preprocessor/strings", - "preprocessor/if", - "preprocessor/define", - "preprocessor/include", - "preprocessor/import", - "preprocessor/error" - ], "Testing": [ "testing/testing", "testing/testing-tickets",