defmodule Kinda.CodeGen.NIF do
alias Kinda.CodeGen.{Function, Type}
@type dirty() :: :io | :cpu | false
@type t() :: %__MODULE__{
wrapper_name: nil | String.t(),
zig_name: nil | String.t(),
nif_name: nil | String.t(),
arity: integer(),
ret: String.t(),
dirty: dirty()
}
defstruct zig_name: nil, nif_name: nil, arity: 0, ret: nil, dirty: false, wrapper_name: nil
def from_function(%Function{name: name, args: args, ret: ret}) do
%__MODULE__{
wrapper_name: name,
zig_name: name,
arity: length(args),
ret: ret
}
end
# TODO: make this extensible
def from_resource_kind(%Type{module_name: module_name, kind_functions: kind_functions}) do
for {f, a} <-
[
ptr: 1,
ptr_to_opaque: 1,
opaque_ptr: 1,
array: 1,
mut_array: 1,
primitive: 1,
make: 1,
dump: 1,
make_from_opaque_ptr: 2,
array_as_opaque: 1
] ++ kind_functions do
%__MODULE__{
nif_name: Module.concat(module_name, f),
arity: a
}
end
end
# if zig_name is nil this NIF should be registered by other way. For instance, functions of resource kinds.
def gen(%__MODULE__{zig_name: nil}), do: ""
def gen(%__MODULE__{zig_name: zig_name, nif_name: nif_name, arity: arity, dirty: dirty}) do
dirty_flag =
case dirty do
:cpu -> "1"
:io -> "2"
false -> "0"
end
"""
e.ErlNifFunc{.name = "#{nif_name}", .arity = #{arity}, .fptr = #{zig_name}, .flags = #{dirty_flag}},
"""
end
end