-
Notifications
You must be signed in to change notification settings - Fork 68
Expand file tree
/
Copy pathffi.ex
More file actions
73 lines (59 loc) · 1.92 KB
/
ffi.ex
File metadata and controls
73 lines (59 loc) · 1.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
defmodule ElixirScript.FFI do
@moduledoc """
The foreign function interface for interacting with JavaScript
To define a foreign module, make a new module and add `use ElixirScript.FFI`. to it
To define foreign functions, use the `foreign` macro.
Here is an example of a foreign module for a JSON module
```elixir
defmodule MyApp.JSON do
use ElixirScript.FFI
foreign stringify(map)
foreign parse(string)
end
```
Foreign modules map to JavaScript files that export functions defined with the `foreign` macro.
ElixirScript expects JavaScript modules to be in the `priv/elixir_script` directory.
These modules are copied to the output directory upon compilation.
For our example, a JavaScript file must be placed at `priv/elixir_script/my_app/json.js`.
It looks like this
```javascript
export default {
stringify: JSON.stringify,
parse: JSON.parse
}
```
"""
defmacro __using__(opts) do
quote do
import ElixirScript.FFI
Module.register_attribute __MODULE__, :__foreign_info__, persist: true
@__foreign_info__ %{
path: Macro.underscore(__MODULE__),
name: Enum.join(Module.split(__MODULE__), "_"),
global: unquote(Keyword.get(opts, :global, false))
}
end
end
@doc """
Defines a JavaScript function to be called from Elixir modules
To define a foreign function, pass the name and arguments to `foreign`
```elixir
foreign my_js_function(arg1, arg2, arg3)
```
"""
defmacro foreign({name, _, args}) do
args = Enum.map(args, fn
{:\\, meta0, [{name, meta, atom}, value]}->
name = String.to_atom("_" <> Atom.to_string(name))
{:\\, meta0, [{name, meta, atom}, value]}
{name, meta, atom} ->
name = String.to_atom("_" <> Atom.to_string(name))
{name, meta, atom}
other ->
other
end)
quote do
def unquote(name)(unquote_splicing(args)), do: nil
end
end
end