-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
move contributing.md and add script_modules.md
- Loading branch information
1 parent
11157dd
commit 5861d12
Showing
3 changed files
with
207 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
<!-- | ||
SPDX-FileCopyrightText: Stone Tickle <[email protected]> | ||
SPDX-License-Identifier: GPL-3.0-only | ||
--> | ||
|
||
# Script Modules | ||
|
||
With muon, you can write modules in an extended form of the meson dsl. This is | ||
for a number of reasons: | ||
|
||
- Many meson modules are effectively reusable chunks of meson code (calls to | ||
dependency, custom\_target, etc.), so it is not necessary to access things | ||
that a native module has access to like the interpreter state. | ||
- Lowering the bar for module contributions (this is important because they | ||
often involve specific tools I have no experience with/interest in). | ||
- Potential to some day share module code with other meson implementations. | ||
|
||
That last point is a bit pie in the sky, but at least this makes it technically | ||
possible from muon's point of view and proves that it has value. | ||
|
||
## Writing a new script module | ||
|
||
All script modules live at `src/script/modules/<module_name>.meson`. After | ||
adding a new module, you must modify `src/script/meson.build` to register it. | ||
muon will embed the module source text as a char[] in the built executable, and | ||
when the module is import()ed that source will be interpreted. | ||
|
||
## Module structure | ||
|
||
A script module consists of functions that perform the various module | ||
operations, with a return statement at the bottom of the file that exports those | ||
functions. | ||
|
||
``` | ||
func func1() | ||
endfunc | ||
func func2() | ||
endfunc | ||
return { | ||
'func1': func1, | ||
'func2': func2, | ||
} | ||
``` | ||
|
||
The final `return` at module scope is what "exports" the functions to module | ||
consumers. The returned object must be of type `dict[func]`. | ||
|
||
## Functions | ||
|
||
Function definition is started with the `func` keyword followed by an | ||
identifier, and a list of arguments enclosed in parenthesis. If the function | ||
returns a value it must specify the type of that value by adding `-> <type>` | ||
after the argument list. | ||
|
||
Positional and keyword arguments are supported in the argument list. Positional | ||
arguments must come first. Keyword arguments are specified by adding a colon | ||
(:) to the end of the argument followed by an optional default value. | ||
All arguments must also specify their type by following the argument name with a | ||
type specifier. | ||
|
||
Examples: | ||
|
||
``` | ||
func a() -> int | ||
return 1 | ||
endfunc | ||
func b(arg1 int) -> int | ||
return arg1 | ||
endfunc | ||
func b(arg1 int, kw str:, kw_with_default str: 'default') | ||
message(arg1) | ||
message(kw) | ||
message(kw_with_default) | ||
endfunc | ||
``` | ||
|
||
## Scope | ||
|
||
Scope generally works like other interpreted languages. | ||
|
||
Modules have their own scope and cannot access any external variables (save | ||
builtins such as meson, build\_machine, etc.). | ||
|
||
Functions also get their own scope, but can see variables that have been | ||
declared in parent scopes prior to the function definition. Function | ||
definitions also capture their scope. | ||
|
||
Example: | ||
|
||
``` | ||
func a() -> func | ||
i = 0 | ||
func b() -> int | ||
i += 1 | ||
return i | ||
endfunc | ||
return b | ||
endfunc | ||
counter = a() | ||
counter() #=> 1 | ||
counter() #=> 2 | ||
new_counter = a() | ||
new_counter() #=> 1 | ||
new_counter() #=> 2 | ||
counter() #=> 3 | ||
``` | ||
|
||
## Type specifiers | ||
|
||
Type specifiers take the form of the ones found in the meson docs. The | ||
following types are allowed: | ||
|
||
- `void` | ||
- `compiler` | ||
- `dep` | ||
- `meson` | ||
- `str` | ||
- `int` | ||
- `list` | ||
- `dict` | ||
- `bool` | ||
- `file` | ||
- `build_tgt` | ||
- `subproject` | ||
- `build_machine` | ||
- `feature` | ||
- `external_program` | ||
- `python_installation` | ||
- `runresult` | ||
- `cfg_data` | ||
- `custom_tgt` | ||
- `test` | ||
- `module` | ||
- `install_tgt` | ||
- `env` | ||
- `inc` | ||
- `option` | ||
- `disabler` | ||
- `generator` | ||
- `generated_list` | ||
- `alias_tgt` | ||
- `both_libs` | ||
- `typeinfo` | ||
- `func` | ||
- `source_set` | ||
- `source_configuration` | ||
|
||
In addition, a value that can take one of many types can be specified by writing | ||
multiple types separated with a `|`. | ||
|
||
``` | ||
int|str | ||
dict|list|str | ||
``` | ||
|
||
There are a few preset combinations of types: | ||
|
||
- `any` - all of the above types except `void` | ||
- `exe` - `str|file|external_program|python_installation|build_tgt|custom_tgt` | ||
|
||
`dict` and `list` should also be followed by a sub-type enclosed in square | ||
brackets. | ||
|
||
``` | ||
dict[str] | ||
dict[str|int] | ||
``` | ||
|
||
Finally, you can wrap the entire type in `glob[<type>]` or `listify[<type>]` to | ||
get the special argument handling detailed in doc/contributing.md (search for | ||
`TYPE_TAG_{GLOB,LISTIFY}`. | ||
|
||
## Additional built-in functions | ||
|
||
Various additional builtin functions are avaliable: | ||
|
||
- `serial_load(path str) -> any` - load a serialized object from a file | ||
- `serial_dump(path str, obj any)` - serialize and save an object to a file | ||
- `is_void(arg any) -> bool` - check if arg is the value void. This can be used | ||
to check if a kwarg with no default value has been set. | ||
- `typeof(arg any) -> str` - returns the type of an object. | ||
- `list.delete(index int)` - delete the element from list at the specefied index | ||
- `dict.delete(key str)` - delete key from dict | ||
|
||
The `fs` module also has additonal functions: | ||
|
||
- `copy(src str|file, dest str)` - copy a file from src to dest | ||
- `write(dest str|file, data str)` - write `data` to `dest` | ||
- `cwd() -> str` - returns muon's current working directory | ||
- `mkdir(path str)` - make the directory at `path` | ||
- `is_basename(path str) -> bool` - true if str contains no path separators | ||
- `is_subpath(base str, sub str) -> bool` - true if `sub` is a subpath of `base` | ||
- `add_suffix(path str, suff str) -> str` - add the suffix `suff` to `path` | ||
- `make_absolute(path str) -> str` - prepend cwd to `path` if path is relative | ||
- `relative_to(base str, sub str) -> str` - return path `sub` relative to `base` | ||
- `without_ext(path str) -> str` - return path with extension removed | ||
to it, otherwise return path | ||
- `executable(path str) -> str` - if path has no path separators, prepend './' |