Packages
orb
0.0.49
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/dsl/defw.ex
defmodule Orb.DSL.Defw do
@moduledoc """
Macros to define WebAssembly functions. Similar to Elixir’s `def` and Nx’s `defn`.
"""
defmacro wasm_mode(mode) do
mode = Macro.expand_literals(mode, __CALLER__)
Module.put_attribute(__CALLER__.module, :wasm_mode, mode)
end
defmacro defw(call, do: block) do
define(call, :public, nil, [], block, __CALLER__)
end
defmacro defw(call, locals, do: block) when is_list(locals) do
define(call, :public, nil, locals, block, __CALLER__)
end
defmacro defw(call, result, do: block) do
define(call, :public, result, [], block, __CALLER__)
end
defmacro defw(call, result, locals, do: block) when is_list(locals) do
define(call, :public, result, locals, block, __CALLER__)
end
defmacro defwp(call, do: block) do
define(call, :private, nil, [], block, __CALLER__)
end
defmacro defwp(call, locals, do: block) when is_list(locals) do
define(call, :private, nil, locals, block, __CALLER__)
end
defmacro defwp(call, result, do: block) do
define(call, :private, result, [], block, __CALLER__)
end
defmacro defwp(call, result, locals, do: block) when is_list(locals) do
define(call, :private, result, locals, block, __CALLER__)
end
defp define(call, visibility, result, locals, block, env) do
mod = env.module
def_kind =
case visibility do
:public -> :def
:private -> :defp
end
elixir_def = define_elixir_def(call, def_kind, result, env)
{func_name, _} = Macro.decompose_call(call)
func_def =
Orb.DSL.__define_func(
call,
visibility,
[
result: result,
locals: locals
],
block,
env
)
quote do
unquote(elixir_def)
with do
table_elems = Module.delete_attribute(unquote(mod), :table)
Module.put_attribute(unquote(mod), :wasm_table_elems, {unquote(func_name), table_elems})
import Orb, only: []
unquote(Orb.__mode_pre(Module.get_attribute(mod, :wasm_mode, Orb.Numeric)))
def __wasm_body__(context) do
previous = super(context)
func = unquote(func_def)
table_elems = unquote(mod).__wasm_table_elems__(func.name)
table_allocations = unquote(mod).__wasm_table_allocations__()
func =
for {mod, key} <- table_elems, reduce: func do
func ->
func
|> Orb.Func.__add_table_elem(
Orb.Table.Allocations.fetch_index!(table_allocations, {mod, key})
)
end
previous ++ [func]
end
defoverridable __wasm_body__: 1
end
end
end
def __define_elixir_def(call, def_kind, result_type, env) do
define_elixir_def(call, def_kind, result_type, env)
end
defp define_elixir_def(
call,
def_kind,
result_type,
%Macro.Env{file: file} = env
) do
{name, func_args} = Macro.decompose_call(call)
{_, meta, _} = call
def_args =
case func_args do
[] ->
[]
[keywords] ->
for {keyword, _type} <- keywords do
Macro.var(keyword, nil)
end
multiple when is_list(multiple) ->
raise CompileError,
line: meta[:line],
file: file,
description:
"Cannot define function with multiple arguments, use keyword list instead."
end
def_call = {name, meta, def_args}
params = Orb.Func.Type.params_from_call_args(func_args, env, meta[:line])
param_types = for %{type: type} <- params, do: type
quote do
unquote(def_kind)(unquote(def_call)) do
Orb.Instruction.typed_call(
unquote(result_type),
unquote(param_types),
case {@wasm_func_prefix, unquote(name)} do
{nil, name} -> name
{prefix, name} -> "#{prefix}.#{name}"
end,
unquote(def_args)
)
end
end
end
end