Updated builtins readme to include information about LowLevel

This commit is contained in:
Chad Stearns 2020-07-22 20:02:57 -04:00
parent 11e63270c3
commit fe48ff323b

View File

@ -1,6 +1,6 @@
# So you want to add a builtin?
Builtins are the functions and modules that are implicitly imported into every module. Some of them compile down to llvm, others need to be constructed and defined. Making a new builtin means touching many files. Here is what it takes:
Builtins are the functions and modules that are implicitly imported into every module. Some of them compile down to llvm, others need to be constructed and defined. Making a new builtin means touching many files. Lets make it easy for you and just list out which modules you need to visit to make a builtin. Here is what it takes:
### module/src/symbol.rs
@ -12,6 +12,44 @@ But we can use these values and some of these are necessary for implementing bui
- ..writing `List.#getUnsafe` that has the dangerous signature of `List elem, Int -> elem` in LLVM
- ..writing `List elem, Int -> Result elem [ OutOfBounds ]*` in a type safe way that uses `getUnsafe` internally, only after it checks if the `elem` at `Int` index exists.
### can/src/builtins.rs
Right at the top of this module is a function called `builtin_defs`. All this is doing is mapping the `Symbol` defined in `module/src/symbol.rs`, to its implementation. Some of the builtins are quite complex, such as `list_get`, for the reasons mentioned in the previous section: `list_get` returns tags, and it defers to lower-level functions via an if statement.
Lets look at `List.repeat : elem, Int -> List elem`, which is more straight forward, and points directly to its lower level implementation:
```
fn list_repeat(symbol: Symbol, var_store: &mut VarStore) -> Def {
let elem_var = var_store.fresh();
let len_var = var_store.fresh();
let list_var = var_store.fresh();
let body = RunLowLevel {
op: LowLevel::ListRepeat,
args: vec![
(elem_var, Var(Symbol::ARG_1)),
(len_var, Var(Symbol::ARG_2)),
],
ret_var: list_var,
};
defn(
symbol,
vec![(elem_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)],
var_store,
body,
list_var,
)
}
```
In these builtin definitions you will need to say what the arguments are, and what types those arguments have. For `List.repeat`, the arguments are the `elem_var` and the `len_var`. So in both the `body` and `defn` we list these arguments in a vector, with the `Symobl::ARG_1` adn` Symvol::ARG_2` designating which argument is which.
Since `List.repeat` is implemented entirely as low level functions, its `body` is a `RunLowLevel`, and the `op` is `LowLevel::ListRepeat`. Lets talk about `LowLevel` in the next section.
## Connecting the definition to the implementation
### module/src/low_level.rs
This `LowLevel` thing connects the builtin defined in this module to its implementation. Its referenced in `can/src/builtins.rs` and it is used in `gen/src/llvm/build.rs`.
## Bottom level LLVM values and functions
### gen/src/llvm/build.rs
This is where bottom-level functions that need to be written as LLVM are created. If the function leads to a tag thats a good sign it should not be written here in `build.rs`. If its simple fundamental stuff like `INT_ADD` then it certainly should be written here.
@ -21,6 +59,6 @@ This is where bottom-level functions that need to be written as LLVM are created
If the function you are making is _not_ low level or returns something like a tag, then it should probably be written here by means of lower level functions written in `build.rs`.
## Letting the compiler know these functions exist
Its one thing to actually write these functions, its _another_ thing to let the Roc compiler know they exist. You have to tell the compiler "Hey, this function exists, and it has this type signature". That happens in these modules:
Its one thing to actually write these functions, its _another_ thing to let the Roc compiler know they exist as part of the standard library. You have to tell the compiler "Hey, this function exists, and it has this type signature". That happens in these modules:
### builtins/src/std.rs
### builtins/src/unique.rs