defmodule Orb.DefwDSL do 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 defwi(call, do: block) do define(call, :internal, nil, [], block, __CALLER__) end defmacro defwi(call, locals, do: block) when is_list(locals) do define(call, :internal, nil, locals, block, __CALLER__) end defmacro defwi(call, result, do: block) do define(call, :internal, result, [], block, __CALLER__) end defmacro defwi(call, result, locals, do: block) when is_list(locals) do define(call, :internal, 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 func_visibility = case visibility do :internal -> :private other -> other end def_kind = case visibility do :public -> :def :internal -> :def :private -> :defp end ex_def = define_elixir_def(call, def_kind, result, env) wasm = Orb.DSL.__define_func(call, func_visibility, [result: result, locals: locals], block, env) quote do unquote(ex_def) Orb.wasm do unquote(wasm) end end end defp define_elixir_def(call, def_kind, result, %Macro.Env{file: file}) do {name, func_args} = Macro.decompose_call(call) {_, meta, _} = call # arity = length(args) 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} quote do unquote(def_kind)(unquote(def_call)) do Orb.Instruction.typed_call( unquote(result), case {@wasm_func_prefix, unquote(name)} do {nil, name} -> name {prefix, name} -> "#{prefix}.#{name}" end, unquote(def_args) ) end end end end