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
Update the Learn Alan page with the new GBuffer behavior, Unwrap{T}, and fill in binding to platform language libraries that I forgot to do before (#107)
In Alan, there's one more buffer-like type, the `GBuffer{T}` types. This type is constructed from either a `Buffer` or `Array`. The type sits in-between the two in that its length is not known at compile time, but it cannot be changed once constructed. This represents a block of memory on the GPU, which you can set at construction time (from a buffer or array).
732
-
733
-
!!! note
734
-
735
-
Right now, this type isn't properly generic, but will be before the release of Alan 0.2.0. TODO: Delete this note.
731
+
In Alan, there's one more buffer-like type, the `GBuffer{T}` type. This type is constructed from either a `Buffer` or `Array`. The type sits in-between the two in that its length is not known at compile time, but it cannot be changed once constructed. This represents a block of memory on the GPU, which you can set at construction time (from a buffer or array).
736
732
737
733
This type cannot be accessed directly at all, it must be explicitly `read` back into an array before it can be accessed, but it can be included in a `GPGPU` execution plan and mutated by that GPGPU compute. The `GPGPU` type can be worked with directly, but most of the time is hidden behind functions that manipulate the `GBuffer` type.
738
734
739
735
```rs
740
736
exportfnmain {
741
-
GBuffer([1, 2, 3, 4])
737
+
GBuffer([1.i32, 2.i32, 3.i32, 4.i32])
742
738
.map(fn (val:gi32) =val*2)
743
739
.read
744
740
.print; // Prints [2, 4, 6, 8]
@@ -1098,11 +1094,7 @@ And we can now `vec1 .+ vec2` in our code. The benefits here are:
1098
1094
1099
1095
## Binding Functions and Types from Rust (or Javascript)
1100
1096
1101
-
!!! note
1102
-
1103
-
Currently only Rust binding exists and that's what the documentation currently covers, but before Alan v0.2.0 it is intended to modify the binding syntax to also define bindings for Javascript
1104
-
1105
-
Beyond defining functions and types in Alan, you may also bind functions and types to Rust functions and types. This binding process trusts you completely that the binding has been specified correctly, so be sure that you're doing so.
1097
+
Beyond defining functions and types in Alan, you may also bind functions and types to Rust or Javascript functions and types. This binding process trusts you completely that the binding has been specified correctly, so be sure that you're doing so.
1106
1098
1107
1099
### Binding Functions
1108
1100
@@ -1127,7 +1119,7 @@ The `::` symbol is an alias for the `Call{N, F}` type, specifying a function cal
1127
1119
1128
1120
!!! note
1129
1121
1130
-
The `Call{N, F}` type requires a fully-defined function type, including the return type, for any function being bound from Rust (or Javascript in the future). Alan's type inference cannot operate on a language it wasn't designed for, so it must be told all of the necessary information ahead of time to work.
1122
+
The `Call{N, F}` type requires a fully-defined function type, including the return type, for any function being bound from Rust or Javascript. Alan's type inference cannot operate on a language it wasn't designed for, so it must be told all of the necessary information ahead of time to work.
1131
1123
1132
1124
In fact, you could use this syntax with any type that produces an automatically-defined constructor function, so if you wanted to create an alias for a struct, but only when constructing it, you could do so:
This defines an `eq` function for 8-bit integers, binding it to Rust's `==` operator, but indicating to Alan that it should dereference the arguments when passing them to the operator. These various generic types allow you to annotate the binding, eliminating the need for writing wrapper functions in Rust.
1163
1155
1156
+
### Binding Functions from Platform-specific Libraries
1157
+
1158
+
There are a collection of types involved in specifying dependencies stored on [crates.io](https://crates.io) and [npm](https://npmjs.com) that you can use in conjunction with the `Call{N, F}` type to bind to 3rd party libraries in whichever host language you choose to compile to.
1159
+
1160
+
These are:
1161
+
1162
+
*`Import{N, D}` - specifying the name of the function or type to import from the dependency. Also bound as the `<-` type operator.
1163
+
*`From{D}` - Special syntactic sugar that uses the name of the type or function declaration to determine the name of the type or function to import. Bound to the `<--` type operator.
1164
+
*`Dependency{N, V}` - specifying the name and version (or raw git URL) of the dependency. Also bound as the `@` type operator.
1165
+
*`Rust{D}` - specifying that this is a Rust crate.
1166
+
*`Nodejs{D}` - specifying that this is an NPM package.
1167
+
1168
+
!!! note
1169
+
1170
+
It is intended for `Import{N, D}` and `From{D}` to both be bound to `<-`, with `Import{N, D}` as an infix operator and `From{D}` as a prefix operator, but some refactoring is needed in the compiler to allow the same symbol to bind to different operators.
1171
+
1172
+
You use three of the five of these types in place of the `N` argument of `Call{N, F}` to specify a platform-native library function or type to import. Eg:
1173
+
1174
+
```rs
1175
+
fn{Rs} escapeCall{Import{"regex_syntax::escape", Rust{Dependency{"regex-syntax", "0.8.5"}}}, Function{string, string}}; // Binds the `escape` function from `regex-syntax`
1176
+
fn{Rs} escape"regex_syntax::escape"<-Rust{"regex-syntax"@"0.8.5"} ::string->string; // Same binding but using type operators where possible
1177
+
fn{Js} yamlLoad Call{Import{"js_yaml.load", Nodejs{Dependency{"js-yaml", "4.1.0"}}}, Function{string, JSObject}}; // Binds the `load` function from `js-yaml` (Alan doesn't have a JSObject type, yet, so good luck with that part!)
1178
+
fn{Js} yamlLoad "js_yaml.load"<-Nodejs{"js-yaml"@"4.1.0"} ::string->JSObject; // Same binding but using type operators where possible
1179
+
```
1180
+
1164
1181
!!! note
1165
1182
1166
-
Currently you can bind standard library functions and a set of blessed third-party Rust libraries only. Before release this syntax will be extended to allow you to specify packages you wish to install from Cargo during the build process.
1183
+
The conditional compilation on the function definitions when importing libraries native to the platform language is **highly recommended** to prevent compilation failures if/when your code is targeting a different platform language.
1167
1184
1168
-
At the same time as this syntax change, binding Javascript functions will also be added to allow compiling to Javascript for use in the browser, which will similarly allow you to specify NPM packages to include in the build process.
1185
+
Ideally if you need native code, you have paired `fn{Rs}` and `fn{Js}` bindings so your code can seamlessly compile to the browser as well as natively. Alan's root scope and standard library follow this advice.
1186
+
1187
+
For now, you must include the name of the library the function is coming from in the binding string for this to work. In Rust it's separated with `::` between the library name and the thing to import and in Javascript it is separated with `.`. In Javascript, the compiler automatically converts `-` in a package name to `_` for the variable name the package occupies.
1169
1188
1170
1189
### Binding Types
1171
1190
@@ -1199,6 +1218,21 @@ Bound functions and types are tricky to work with, but provide a zero-cost FFI t
1199
1218
type{Rs} Dom = Fail{"This library can only be used when compiled to Javascript, as Rust does not have a DOM."}
1200
1219
```
1201
1220
1221
+
### Binding Types from Platform-specific Libraries
1222
+
1223
+
The same collection of types involved in binding functions from platform languages works identically for types. Well, sort-of identically. Javascript doesn't have types, so what happens there? The type is just an internal construct within the compiler to prevent you from accidentally assigning the wrong kind of value to the wrong variable, and is not emitted in the code generation at all. It just needs to be "distinct", so it's *recommended* to write it in a similar way, with Javascript class names being a decent analog to use.
1224
+
1225
+
In neither Rust nor Javascript binding will *constructor functions* be automatically bound for these types; they're opaque to the compiler, so you also need to bind a function to construct them (and by convention that function name should match the type name, and this is where a Javascript library's class would actually be imported, as the constructor function).
1226
+
1227
+
For Rust, though, these type bindings must be precise, not just unique, or the generated code will be incorrect. Similar to how import declaration takes the first generic argument of the `Call{N, F}` type, when you bind a type, it takes place of the first generic argument of the `Binds{T, ...}` type:
1228
+
1229
+
```rs
1230
+
type{Rs} HashMap{K, V} =Binds{"hashbrown::HashMap"<-Rust{"hashbrown"@"0.15.2"}, K, V}; // Binding the hashbrown high-performance HashMap type
1231
+
type{Js} Moment=Binds{"Moment"<-Nodejs{"moment"@"2.30.1"}}; // Binding the Moment datetime type
1232
+
```
1233
+
1234
+
You can bind generic functions in Alan as you can see here, but technically what happens under the hood is that a concrete type is constructed for each set of generic arguments you used in your Alan code; the actual generic type is never emitted to the Rust compiler. This is the same thing Rust itself does when generating your binary, effectively duplicating the generic type for each concrete instance of it, so this should have no impact on the size of the resulting binary.
1235
+
1202
1236
## Conditional Statements
1203
1237
1204
1238
Currently in Alan, Conditional statements are implemented solely with the `if` functions, which take a boolean and one or two functions that take zero arguments and optionally return a value.
0 commit comments