Packages
orb
0.2.2
0.2.2
0.2.1
0.2.0
0.1.1
0.1.0
0.0.51
0.0.49
0.0.48
0.0.47
0.0.46
0.0.45
0.0.44
0.0.43
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.18
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
retired
0.0.11
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.4
0.0.3
0.0.2
0.0.1
DSL for WebAssembly
Current section
Files
Jump to
Current section
Files
lib/orb/import.ex
defmodule Orb.Import do
@moduledoc """
Define an interface to be imported into WebAssembly.
Each function declaration is turned into an `(import)` WebAssembly instruction.
```elixir
defmodule Log do
use Orb.Import, name: :log
defw logi32(value: I32)
defw logi64(value: I64)
end
defmodule Time do
use Orb.Import, name: :time
defw get_unix_time(), I64
end
defmodule Example do
use Orb
Orb.Import.register(Log)
Orb.Import.register(Time)
defw example() do
Log.logi32(99)
Log.logi64(Time.get_unix_time())
end
end
```
"""
defstruct [:module, :name, :type]
defmacro __using__(opts) do
quote bind_quoted: [opts: opts] do
import Orb.DSL.Defw, only: []
import Orb.Import.DSL
alias Orb.{I32, I64, F32, F64}
@orb_import_namespace Keyword.get(opts, :name) ||
raise("Option :name must be passed to `use Orb.Import`")
# Module.register_attribute(__MODULE__, :wasm_imports, accumulate: true, persist: true)
def __wasm_imports__(_context), do: []
defoverridable __wasm_imports__: 1
with do
require Orb
Orb.set_func_prefix(inspect(__MODULE__))
end
end
end
@doc """
Register an import `module` under `namespace`.
The `module` is defined via `use Orb.Import`. The `namespace` is the local name the import is registered under.
For each function defined within `module` an `(import)` instruction is defined in the outputted WebAssembly:
```wasm
(module $example
(import "namespace" "function1" (func $function1 (param $a i32) (result i32)))
(import "namespace" "function2" (func $function2 (param $a i32) (result i32)))
(import "namespace" "function3" (func $function3 (param $a i32) (result i32)))
)
```
"""
@doc since: "0.0.46"
defmacro register(module) do
quote do
@wasm_imports (for imp <- unquote(module).__wasm_imports__(nil) do
imp
end)
end
end
defimpl Orb.ToWat do
def to_wat(%Orb.Import{module: nil, name: name, type: type}, indent) do
[indent, ~S|(import "|, to_string(name), ~S|" |, Orb.ToWat.to_wat(type, ""), ?)]
end
def to_wat(%Orb.Import{module: module, name: name, type: type}, indent) do
[
indent,
~S|(import "|,
to_string(module),
~S|" "|,
to_string(name),
~S|" |,
Orb.ToWat.to_wat(type, ""),
?)
]
end
end
defmodule DSL do
@moduledoc """
DSL for declaring within Elixir module that get converted to `(import …)` expressions in WebAssembly.
"""
@doc """
Declare the name and signature of function that will be imported.
```elixir
defmodule Log do
use Orb.Import, name: :log
defw(int32(a: I32))
defw(int64(a: I64))
defw(two_int32(a: I32, b: I32))
end
```
"""
defmacro defw(call, result_type \\ nil) do
alias Elixir.Orb.{Func, Import}
env = __CALLER__
# call = Macro.expand_once(call, __ENV__)
{name, args} = Macro.decompose_call(call)
line =
case call do
{_, meta, _} -> meta[:line]
_ -> env.line
end
params = Func.Type.params_from_call_args(args, env, line)
result_type = result_type |> Macro.expand_literals(env)
ex_def = Elixir.Orb.DSL.Defw.__define_elixir_def(call, :def, result_type, env)
quote do
unquote(ex_def)
with do
def __wasm_imports__(context) do
full_name =
case {inspect(__MODULE__), unquote(name)} do
{nil, name} -> name
{prefix, name} -> "#{prefix}.#{name}"
end
imp = %Import{
module: @orb_import_namespace,
name: unquote(name),
type: Func.Type.new(full_name, unquote(Macro.escape(params)), unquote(result_type))
}
super(context) ++ [imp]
end
defoverridable __wasm_imports__: 1
end
end
end
end
end