You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/docs/tutorials/modules.md
+94-92Lines changed: 94 additions & 92 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,96 +24,98 @@ You will still need to dive a bit into the documentation of the project, to know
24
24
25
25
Also, read [the HOWTO guide about module error handling](/docs/reference/module_error_handling) to use the same conventions as the other modules, and [the guidelines about naming convention](/docs/guides/naming) in ArkScript (specifically see the *Modules (C++)* section).
26
26
27
-
section#create-a-module
28
-
h2 Creating a new module
29
-
div.inner-section
30
-
p
31
-
| In your #[a(href="https://github.com/ArkScript-lang/modules") ArkScript-lang/modules] fork, run the Python script as follows #[code python3 shell/createmodules/create.py module_name].
32
-
| This will create a new folder #[code module_name/] for you, alongside a few folders and files needed to get you started.
33
-
p Create a #[code Main.cpp] file in #[code module_name/src/] with the following content:
34
-
pre: code.rainbowjs(data-language="cpp")
35
-
| #include <Ark/Module.hpp>
36
-
|
37
-
| Ark::Value foo(std::vector<Ark::Value>& n [[maybe_unused]], Ark::VM* vm [[maybe_unused]])
38
-
| {
39
-
| return Ark::Value(1);
40
-
| }
41
-
|
42
-
| ARK_API Ark::mapping* getFunctionsMapping()
43
-
| {
44
-
| static Ark::mapping map[] = {
45
-
| { "test:foo", foo },
46
-
|
47
-
| // sentinel
48
-
| { nullptr, nullptr }
49
-
| };
50
-
|
51
-
| return map;
52
-
| }
53
-
p Let's walk through this line by line:
54
-
ul
55
-
li #[code #include <Ark/Module.hpp>] includes basic files from ArkScript to be able to use the VM, instantiates values, and generate the entry point of the module
56
-
li #[code Ark::Value foo(std::vector<Ark::Value>& n [[maybe_unused]], Ark::VM* vm [[maybe_unused]]) {...}] defines a function for our module, taking an argument list from the VM, and a non-owning pointer to the VM
57
-
li #[code ARK_API Ark::mapping* getFunctionsMapping()] declares the entrypoint of our module
58
-
li #[code static Ark::mapping map[] = {...};] creates a mapping of elements to hold the name -> function pointer association, defining the module
59
-
li closing braces are stacked together, and never preceded by a newline
60
-
ul: li note that the given name is #[code "test:foo"]: this is a convention in ArkScript, every module's function must be prefixed by the module name
61
-
li #[code { nullptr, nullptr }]: a sentinel so that the virtual machine where the end of mapping is
62
-
63
-
section#building
64
-
h2 Building your module
65
-
div.inner-section
66
-
p Clone ArkScript wherever you like. Then, you will need to update your CMakeLists.txt to add the following code:
67
-
pre: code.rainbowjs(data-language="cmake")
68
-
| add_subdirectory(path/to/arkscript/ Ark)
69
-
p Then, run #[code cmake . -Bbuild], and build your module with #[code cmake --build build]. It should output a #[code .arkm] file in the current working directory.
70
-
71
-
section#troubleshooting
72
-
h2 Troubleshooting
73
-
div.inner-section
74
-
h3 Storing values in a C++ module
75
-
p
76
-
| Lets say you are making a module to handle a window (to draw on it). You will open it with the API for your system, for example the WinAPI, and get an handle to it.
77
-
| Now you want to be able to modify this window in ArkScript, the solution is simple: creating an UserType holding your handle, and then getting this user type back in
78
-
| your functions and playing with the handle.
79
-
p
80
-
| If you try this as is, it won't work. Or at least, it won't work for more than a function call, because the UserType doesn't become the #[em owner of the handle],
81
-
| it only holds a view (observer pointer) to your resource. That means your resource must continue to live on its own in your module. Because it's a dynamic library,
82
-
| making a global and storing your handle in it will be complicated and in a lot of cases it won't work at all.
83
-
p Here is the trick:
84
-
pre: code.rainbowjs(data-language="cpp")
85
-
| // will always return the same handle once its created
p First, we have a function returning a reference to a static object, which will get initialized only once, even if we call the function a thousand times. Great, we solved the lifetime problem!
115
-
p
116
-
| Then, we have a #[code get_cfs_window] functions. #[em cfs] is the abbreviation for #[em control functions] in ArkScript, they are designed as a shared block of function pointers
117
-
| to handle an object in ArkScript (how to display it on the screen, how to delete it once the memory needs to be fred...)
118
-
p Finally, we have our C++ function which will be bind to ArkScript, creating/receiving the window handle and returning an UserType with the control functions block.
27
+
## Creating a new module
119
28
29
+
In your [ArkScript-lang/modules](https://github.com/ArkScript-lang/modules) fork, run the Python script as follows `python3 shell/createmodules/create.py module_name`. This will create a new folder `module_name/` for you, alongside a few folders and files needed to get you started.
30
+
31
+
Create a `Main.cpp` file in `module_name/src/` with the following content:
32
+
33
+
{{< highlight_arkscript >}}
34
+
#include <Ark/Module.hpp>
35
+
36
+
Ark::Value foo(std::vector<Ark::Value>& n [[maybe_unused]], Ark::VM* vm [[maybe_unused]])
37
+
{
38
+
return Ark::Value(1);
39
+
}
40
+
41
+
ARK_API Ark::mapping* getFunctionsMapping()
42
+
{
43
+
static Ark::mapping map[] = {
44
+
{ "test:foo", foo },
45
+
46
+
// sentinel
47
+
{ nullptr, nullptr }
48
+
};
49
+
50
+
return map;
51
+
}
52
+
{{< /highlight_arkscript >}}
53
+
54
+
Let's walk through this line by line:
55
+
56
+
-`#include <Ark/Module.hpp>` includes basic files from ArkScript to be able to use the VM, instantiates values, and generate the entry point of the module
57
+
-`Ark::Value foo(std::vector<Ark::Value>& n [[maybe_unused]], Ark::VM* vm [[maybe_unused]]) {...}` defines a function for our module, taking an argument list from the VM, and a non-owning pointer to the VM
58
+
-`ARK_API Ark::mapping* getFunctionsMapping()` declares the entrypoint of our module
59
+
-`static Ark::mapping map[] = {...};` creates a mapping of elements to hold the name -> function pointer association, defining the module
60
+
- closing braces are stacked together, and never preceded by a newline
61
+
- note that the given name is `"test:foo"`: this is a convention in ArkScript, every module's function must be prefixed by the module name
62
+
-`{ nullptr, nullptr }`: a sentinel so that the virtual machine where the end of mapping is
63
+
64
+
## Building your module
65
+
66
+
Clone ArkScript wherever you like. Then, you will need to update your CMakeLists.txt to add the following code:
67
+
68
+
```cmake
69
+
add_subdirectory(path/to/arkscript/ Ark)
70
+
```
71
+
72
+
Then, run `cmake . -Bbuild`, and build your module with `cmake --build build`. It should output a `.arkm` file in the current working directory.
73
+
74
+
## Troubleshooting
75
+
76
+
### Storing values in a C++ module
77
+
78
+
Lets say you are making a module to handle a window (to draw on it). You will open it with the API for your system, for example the WinAPI, and get an handle to it. Now you want to be able to modify this window in ArkScript, the solution is simple: creating an UserType holding your handle, and then getting this user type back in your functions and playing with the handle.
79
+
80
+
If you try this as is, it won't work. Or at least, it won't work for more than a function call, because the UserType doesn't become the *owner of the handle*, it only holds a view (observer pointer) to your resource. That means your resource must continue to live on its own in your module. Because it's a dynamic library, making a global and storing your handle in it will be complicated and in a lot of cases it won't work at all.
81
+
82
+
Here is the trick:
83
+
84
+
```cpp
85
+
// will always return the same handle once its created
First, we have a function returning a reference to a static object, which will get initialized only once, even if we call the function a thousand times. Great, we solved the lifetime problem!
118
+
119
+
Then, we have a `get_cfs_window` functions. *cfs* is the abbreviation for *control functions` in ArkScript, they are designed as a shared block of function pointers to handle an object in ArkScript (how to display it on the screen, how to delete it once the memory needs to be fred...)
120
+
121
+
Finally, we have our C++ function which will be bind to ArkScript, creating/receiving the window handle and returning an UserType with the control functions block.
0 commit comments