Packages

plymio_codi: Generating Quoted Forms for Common Code Patterns

Current section

Files

Jump to
plymio_codi lib codi codi.ex
Raw

lib/codi/codi.ex

defmodule Plymio.Codi do
@moduledoc ~S"""
`Plymio.Codi` generates *quoted forms* for common code *patterns*.
The `produce_codi/2` function produces the *quoted forms* for the
*patterns*.
The `reify_codi/2` macro calls `produce_codi/2` and then compiles
the forms.
## Documentation Terms
In the documentation below these terms, usually in *italics*, are used to mean the same thing.
### *opts*
*opts* is a `Keyword` list.
### *form* and *forms*
A *form* is a quoted form (`Macro.t`). A *forms* is a list of zero, one or more *form*s.
### *vekil*
The proxy patterns (see below) use a dictionary called the *vekil*:
The *proxy* can be though of as the *key* while its value (called a
*from*) "realises" to a *form* / *forms*.
The *vekil* implements the `Plymio.Vekil` protocol. If the vekil
given to `new/1` or `update/2` is a `Map` or `Keyword`, it will be
used to create a `Plymio.Vekil.Form` *vekil*.
The *forom* in the *vekil* **must** "realise"
(`Plymio.Vekil.Forom.realise/2`) to *forms*.
It is more efficient to pre-create (ideally at compile time) the
*vekil*; it can be edited later using e.g. `:proxy_put`.
## Options (*opts*)
The first argument to both of these functions is an *opts*.
The canonical form of a *pattern* definition in the *opts* is the
key `:pattern` with an *opts* value specific to the
*pattern* e.g.
[pattern: [pattern: :delegate, name: :fun_one, arity: 1, module: ModuleA]
The value is referred to as the *cpo* below, short for *codi pattern opts*.
**All pattern definitions are normalised to this format.**
However, for convenience, the key can be the *pattern* name
(e.g. `:delegate`) and the value the (pre normalised) *cpo*:
[delegate: [name: :fun_one, arity: 1, module: ModuleA]
This example shows the code produced for the above:
iex> {:ok, {forms, _}} = [
...> delegate: [name: :fun_one, arity: 1, module: ModuleA],
...> ] |> produce_codi
...> forms |> harnais_helper_show_forms!
["@doc(\"Delegated to `ModuleA.fun_one/1`\")",
"defdelegate(fun_one(var1), to: ModuleA)"]
Also, again for convenience, some *patterns* will normalise the
value. For example the `:doc` pattern normalises this:
[doc: "This is a docstring"]
into this:
[pattern: [pattern: doc, doc: "This is a docstring"]
The keys in the *cpo* have aliases. Note the aliases are
pattern-specific. For examples `:args` is both an alias for
`:spec_args` and `:fun_args`. Each pattern below lists its keys' aliases.
### Common Codi Pattern Opts Keys
These are the keys that can appear in a *cpo* as well as the pattern-specific ones:
| Key | Aliases | Role |
| :--- | :--- | :--- |
| `:pattern` | | *the name of the pattern* |
| `:forms_edit` | *:form_edit, :edit_forms, :edit_form* | *forms_edit/2 opts* |
> there are other, internal use, keys that can appear as well.
## Editing Pattern Forms
Most patterns produce *forms*. Individual pattern *forms* can be edited by giving a `:forms_edit` key in the *cpo*
where the value is an *opts* understood by `Plymio.Fontais.Form.forms_edit/2`.
Alternatively the `:forms_edit` can be given in the *opts* to
`produce_codi/2` (or `reify_codi/2`) and will be applied to *all*
produced *forms*.
## Patterns
There are a number of patterns, some having aliases, described below:
| Pattern | Aliases |
| :--- | :--- |
| `:form` | *:forms, :ast, :asts* |
| `:typespec_spec` | *:spec* |
| `:doc` | |
| `:since` | |
| `:delegate` | |
| `:delegate_module` | |
| `:bang` | |
| `:bang_module` | |
| `:query` | |
| `:query_module` | |
| `:proxy_fetch` | *:proxy, :proxies, :proxies_fetch* |
| `:proxy_put` | *:proxies_put* |
| `:proxy_delete` | *:proxies_delete* |
| `:proxy_get` | *:proxies_get* |
| `:struct_get` | |
| `:struct_fetch` | |
| `:struct_put` | |
| `:struct_maybe_put` | |
| `:struct_has?` | |
| `:struct_update` | |
| `:struct_set` | |
| `:struct_export` | |
### Pattern: *form*
The *form* pattern is a convenience to embed arbitrary code.
See `Plymio.Codi.Pattern.Other` for details and examples.
### Pattern: *typespec_spec*
The *typespec_spec* pattern builds a `@spec` module attribute form.
See `Plymio.Codi.Pattern.Typespec` for details and examples.
### Pattern: *doc*
The *doc* pattern builds a `@doc` module attribute form.
See `Plymio.Codi.Pattern.Doc` for details and examples.
### Pattern: *since*
The *since* pattern builds a `@since` module attribute form.
See `Plymio.Codi.Pattern.Other` for details and examples.
### Pattern: *deprecated*
The *deprecated* pattern builds a `@deprecated` module attribute form.
See `Plymio.Codi.Pattern.Other` for details and examples.
### Pattern: *delegate* and *delegate_module*
The *delegate* pattern builds a `Kernel.defdelegate/2` call,
together, optionally, with a `@doc`, `@since`, and/or `@spec`.
The *delegate_module* pattern builds a `Kernel.defdelegate/2` call
for one or more functions in a module. As with `:delegate` a `@doc` and/or `@since`
can be generated at the same time.
See `Plymio.Codi.Pattern.Delegate` for details and examples.
### Pattern: *bang* and *bang_module*
The *bang* pattern builds bang functions
(e.g. `myfun!(arg)`) using existing base functions (e.g. `myfun(arg)`).
The *bang_module* pattern builds a bang function for one or more
functions in a module. As with `:bang` a `@doc` or `@since` can be generated at
the same time.
See `Plymio.Codi.Pattern.Bang` for details and examples.
### Pattern: *query* and *query_module*
The *query* pattern works like *bang* but builds a query function
(e.g. `myfun?(arg)`) using a base function (e.g. `myfun(arg)`).
The *query_module* pattern builds a query function for one or more
functions in a module. As with `:query` a `@doc` or `@since` can be generated at
the same time.
See `Plymio.Codi.Pattern.Query` for details and examples.
### Pattern: *proxy* patterns
The *proxy* patterns manage the *vekil*..
See `Plymio.Codi.Pattern.Proxy` for details and examples.
### Pattern: *struct* patterns
The *struct* patterns create a range of transform functions for a module's struct.
See `Plymio.Codi.Pattern.Struct` for details and examples.
"""
require Plymio.Vekil.Utility, as: VEKILUTIL
require Plymio.Fontais.Option, as: PFO
use Plymio.Fontais.Attribute
use Plymio.Vekil.Attribute
use Plymio.Codi.Attribute
@codi_opts [
{@plymio_vekil_key_vekil, Plymio.Vekil.Codi.__vekil__()}
]
import Plymio.Codi.Error,
only: [
new_error_result: 1
],
warn: false
import Plymio.Fontais.Guard,
only: [
is_value_set: 1,
is_value_unset: 1,
is_value_unset_or_nil: 1
]
import Plymio.Fontais.Option,
only: [
opzioni_flatten: 1,
opts_create_aliases_dict: 1
]
import Plymio.Codi.Utility.Dispatch,
only: [
validate_pattern_dispatch_vector: 1
]
import Plymio.Codi.Utility,
only: [
validate_module_dict: 1,
validate_fun_module: 1
],
warn: false
import Plymio.Codi.CPO,
only: [
cpo_get_status: 2,
cpo_get_patterns: 1,
cpo_put_set_struct_field: 3,
cpo_edit_forms: 1
]
import Plymio.Funcio.Enum.Map.Collate,
only: [
map_collate0_enum: 2
]
@plymio_codi_pattern_dicts @plymio_fontais_the_unset_value
@plymio_codi_pattern_normalisers %{
@plymio_codi_pattern_form => &Plymio.Codi.Pattern.Other.cpo_pattern_form_normalise/1,
@plymio_codi_pattern_doc => &Plymio.Codi.Pattern.Doc.cpo_pattern_doc_normalise/1,
@plymio_codi_pattern_since => &Plymio.Codi.Pattern.Other.cpo_pattern_since_normalise/1,
@plymio_codi_pattern_deprecated =>
&Plymio.Codi.Pattern.Other.cpo_pattern_deprecated_normalise/1,
@plymio_codi_pattern_typespec_spec =>
&Plymio.Codi.Pattern.Typespec.cpo_pattern_typespec_spec_normalise/1,
@plymio_codi_pattern_bang => &Plymio.Codi.Pattern.Bang.cpo_pattern_bang_normalise/1,
@plymio_codi_pattern_bang_module =>
&Plymio.Codi.Pattern.Bang.cpo_pattern_bang_module_normalise/1,
@plymio_codi_pattern_query => &Plymio.Codi.Pattern.Query.cpo_pattern_query_normalise/1,
@plymio_codi_pattern_query_module =>
&Plymio.Codi.Pattern.Query.cpo_pattern_query_module_normalise/1,
@plymio_codi_pattern_delegate =>
&Plymio.Codi.Pattern.Delegate.cpo_pattern_delegate_normalise/1,
@plymio_codi_pattern_delegate_module =>
&Plymio.Codi.Pattern.Delegate.cpo_pattern_delegate_module_normalise/1,
@plymio_codi_pattern_proxy_fetch =>
&Plymio.Codi.Pattern.Proxy.cpo_pattern_proxy_fetch_normalise/1,
@plymio_codi_pattern_proxy_put =>
&Plymio.Codi.Pattern.Proxy.cpo_pattern_proxy_put_normalise/1,
@plymio_codi_pattern_proxy_get =>
&Plymio.Codi.Pattern.Proxy.cpo_pattern_proxy_get_normalise/1,
@plymio_codi_pattern_proxy_delete =>
&Plymio.Codi.Pattern.Proxy.cpo_pattern_proxy_delete_normalise/1,
@plymio_codi_pattern_struct_export =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_export_normalise/1,
@plymio_codi_pattern_struct_update =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_update_normalise/1,
@plymio_codi_pattern_struct_set =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_set_normalise/1,
@plymio_codi_pattern_struct_get =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_get_normalise/1,
@plymio_codi_pattern_struct_get1 =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_get_normalise/1,
@plymio_codi_pattern_struct_get2 =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_get_normalise/1,
@plymio_codi_pattern_struct_fetch =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_fetch_normalise/1,
@plymio_codi_pattern_struct_put =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_put_normalise/1,
@plymio_codi_pattern_struct_maybe_put =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_maybe_put_normalise/1,
@plymio_codi_pattern_struct_has? =>
&Plymio.Codi.Pattern.Struct.cpo_pattern_struct_has_normalise/1
}
@plymio_codi_pattern_express_dispatch %{
@plymio_codi_pattern_form => &Plymio.Codi.Pattern.Other.express_pattern/3,
@plymio_codi_pattern_doc => &Plymio.Codi.Pattern.Doc.express_pattern/3,
@plymio_codi_pattern_since => &Plymio.Codi.Pattern.Other.express_pattern/3,
@plymio_codi_pattern_deprecated => &Plymio.Codi.Pattern.Other.express_pattern/3,
@plymio_codi_pattern_typespec_spec => &Plymio.Codi.Pattern.Typespec.express_pattern/3,
@plymio_codi_pattern_bang => &Plymio.Codi.Pattern.Bang.express_pattern/3,
@plymio_codi_pattern_bang_module => &Plymio.Codi.Pattern.Bang.express_pattern/3,
@plymio_codi_pattern_query => &Plymio.Codi.Pattern.Query.express_pattern/3,
@plymio_codi_pattern_query_module => &Plymio.Codi.Pattern.Query.express_pattern/3,
@plymio_codi_pattern_delegate => &Plymio.Codi.Pattern.Delegate.express_pattern/3,
@plymio_codi_pattern_delegate_module => &Plymio.Codi.Pattern.Delegate.express_pattern/3,
@plymio_codi_pattern_proxy_fetch => &Plymio.Codi.Pattern.Proxy.express_pattern/3,
@plymio_codi_pattern_proxy_put => &Plymio.Codi.Pattern.Proxy.express_pattern/3,
@plymio_codi_pattern_proxy_get => &Plymio.Codi.Pattern.Proxy.express_pattern/3,
@plymio_codi_pattern_proxy_delete => &Plymio.Codi.Pattern.Proxy.express_pattern/3,
@plymio_codi_pattern_struct_update => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_export => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_set => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_get => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_get1 => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_get2 => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_fetch => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_put => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_maybe_put => &Plymio.Codi.Pattern.Struct.express_pattern/3,
@plymio_codi_pattern_struct_has? => &Plymio.Codi.Pattern.Struct.express_pattern/3
}
@plymio_codi_stage_dispatch [
{@plymio_codi_stage_normalise, &__MODULE__.Stage.Normalise.produce_stage/1},
{@plymio_codi_stage_commit, &__MODULE__.Stage.Commit.produce_stage/1},
{@plymio_codi_stage_express, &__MODULE__.Stage.Express.produce_stage/1},
{@plymio_codi_stage_review, &__MODULE__.Stage.Review.produce_stage/1}
]
@plymio_codi_kvs_verb [
# struct
@plymio_codi_field_alias_snippets,
@plymio_codi_field_alias_stage_dispatch,
@plymio_codi_field_alias_patterns,
@plymio_codi_field_alias_pattern_dicts,
@plymio_codi_field_alias_pattern_normalisers,
@plymio_codi_field_alias_pattern_express_dispatch,
@plymio_codi_field_alias_forms,
@plymio_codi_field_alias_forms_edit,
@plymio_codi_field_alias_vekil,
@plymio_codi_field_alias_module_fva_dict,
@plymio_codi_field_alias_module_doc_dict,
# virtual
@plymio_codi_pattern_alias_form,
@plymio_codi_pattern_alias_doc,
@plymio_codi_pattern_alias_typespec_spec,
@plymio_codi_pattern_alias_since,
@plymio_codi_pattern_alias_deprecated,
@plymio_codi_pattern_alias_bang,
@plymio_codi_pattern_alias_bang_module,
@plymio_codi_pattern_alias_query,
@plymio_codi_pattern_alias_query_module,
@plymio_codi_pattern_alias_delegate,
@plymio_codi_pattern_alias_delegate_module,
@plymio_codi_pattern_alias_proxy_fetch,
@plymio_codi_pattern_alias_proxy_put,
@plymio_codi_pattern_alias_proxy_get,
@plymio_codi_pattern_alias_proxy_delete,
@plymio_codi_pattern_alias_struct_export,
@plymio_codi_pattern_alias_struct_update,
@plymio_codi_pattern_alias_struct_set,
@plymio_codi_pattern_alias_struct_get,
@plymio_codi_pattern_alias_struct_get1,
@plymio_codi_pattern_alias_struct_get2,
@plymio_codi_pattern_alias_struct_fetch,
@plymio_codi_pattern_alias_struct_put,
@plymio_codi_pattern_alias_struct_maybe_put,
@plymio_codi_pattern_alias_struct_has?,
@plymio_codi_key_alias_pattern
]
@plymio_codi_dict_verb @plymio_codi_kvs_verb
|> opts_create_aliases_dict
@plymio_codi_defstruct [
{@plymio_codi_field_snippets, @plymio_fontais_the_unset_value},
{@plymio_codi_field_stage_dispatch, @plymio_codi_stage_dispatch},
{@plymio_codi_field_patterns, @plymio_fontais_the_unset_value},
{@plymio_codi_field_pattern_express_dispatch, @plymio_codi_pattern_express_dispatch},
{@plymio_codi_field_pattern_dicts, @plymio_codi_pattern_dicts},
{@plymio_codi_field_pattern_normalisers, @plymio_codi_pattern_normalisers},
{@plymio_codi_field_forms, @plymio_fontais_the_unset_value},
{@plymio_codi_field_forms_edit, @plymio_fontais_the_unset_value},
{@plymio_codi_field_vekil, @plymio_fontais_the_unset_value},
{@plymio_codi_field_module_fva_dict, @plymio_fontais_the_unset_value},
{@plymio_codi_field_module_doc_dict, @plymio_fontais_the_unset_value}
]
defstruct @plymio_codi_defstruct
@type t :: %__MODULE__{}
@type kv :: Plymio.Fontais.kv()
@type opts :: Plymio.Fontais.opts()
@type error :: Plymio.Fontais.error()
@type result :: Plymio.Fontais.result()
@type form :: Plymio.Fontais.form()
@type forms :: Plymio.Fontais.forms()
@doc false
def update_canonical_opts(opts, dict \\ @plymio_codi_dict_verb) do
opts |> PFO.opts_canonical_keys(dict)
end
[
:state_base_package,
:state_defp_update_field_header,
:state_defp_update_proxy_field_normalise
]
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_rename_atoms, [proxy_field: @plymio_codi_field_module_fva_dict]},
{@plymio_fontais_key_rename_funs, [proxy_field_normalise: :validate_module_dict]}
]
)
defp update_field(%__MODULE__{} = state, {k, v})
when k == @plymio_codi_field_vekil do
cond do
Plymio.Vekil.Utility.vekil?(v) ->
{:ok, state |> struct!([{@plymio_codi_field_vekil, v}])}
true ->
with {:ok, vekil} <- [{@plymio_vekil_field_dict, v}] |> Plymio.Vekil.Form.new() do
{:ok, state |> struct!([{@plymio_codi_field_vekil, vekil}])}
else
{:error, %{__exception__: true}} = result -> result
end
end
end
defp update_field(%__MODULE__{} = state, {k, v})
when k in @plymio_codi_pattern_types or k == @plymio_codi_key_pattern do
state |> add_snippets({k, v})
end
defp update_field(%__MODULE__{} = state, {k, v})
when k == @plymio_codi_field_pattern_express_dispatch do
with {:ok, dispatch_vector} <- v |> validate_pattern_dispatch_vector do
state |> struct!([{@plymio_codi_field_pattern_express_dispatch, dispatch_vector}])
else
{:error, %{__exception__: true}} = result -> result
end
end
:state_defp_update_proxy_field_keyword
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_rename_atoms, [proxy_field: @plymio_codi_field_forms_edit]}
]
)
:state_defp_update_proxy_field_opzioni_validate
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_rename_atoms, [proxy_field: @plymio_codi_field_patterns]}
]
)
:state_defp_update_proxy_field_passthru
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_rename_atoms, [proxy_field: @plymio_codi_field_snippets]}
]
)
:state_defp_update_field_unknown
|> VEKILUTIL.reify_proxies(@codi_opts)
@plymio_codi_defstruct_updaters @plymio_codi_defstruct
for {name, _} <- @plymio_codi_defstruct_updaters do
update_fun = "update_#{name}" |> String.to_atom()
@doc false
def unquote(update_fun)(%__MODULE__{} = state, value) do
state |> update([{unquote(name), value}])
end
end
@plymio_codi_defstruct_reseters @plymio_codi_defstruct
|> Keyword.take([
@plymio_codi_field_snippets,
@plymio_codi_field_patterns
])
for {name, _} <- @plymio_codi_defstruct_reseters do
reset_fun = "reset_#{name}" |> String.to_atom()
@doc false
def unquote(reset_fun)(%__MODULE__{} = state, value \\ @plymio_fontais_the_unset_value) do
state |> update([{unquote(name), value}])
end
end
defp add_snippets(state, patterns)
defp add_snippets(%__MODULE__{@plymio_codi_field_snippets => snippets} = state, new_snippets) do
snippets
|> case do
x when is_value_unset(x) ->
state |> update_snippets(List.wrap(new_snippets))
x when is_list(x) ->
state |> update_snippets(x ++ List.wrap(new_snippets))
end
end
[
:doc_false,
:workflow_def_produce
]
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_postwalk,
fn
{:express, ctx, args} -> {:produce_recurse, ctx, args}
:PRODUCESTAGESTRUCT -> __MODULE__
x -> x
end}
]
)
@doc false
@since "0.1.0"
@spec produce_recurse(t) :: {:ok, {opts, t}} | {:error, error}
def produce_recurse(codi)
def produce_recurse(%__MODULE__{@plymio_codi_field_snippets => snippets} = state)
when is_value_set(snippets) do
with {:ok, {_product, %__MODULE__{} = state}} <-
state |> __MODULE__.Stage.Normalise.normalise_snippets(),
{:ok, %__MODULE__{} = state} = state |> reset_snippets,
{:ok, {_product, %__MODULE__{}}} = result <- state |> produce_recurse do
result
else
{:error, %{__exception__: true}} = result -> result
end
end
def produce_recurse(%__MODULE__{} = state) do
with {:ok, {product, state}} <- state |> produce_stages,
{:ok, cpos} <- product |> cpo_get_patterns do
# unless all cpos have status "done" need to recurse. default is done.
cpos
|> map_collate0_enum(fn cpo -> cpo |> cpo_get_status(@plymio_codi_status_done) end)
|> case do
{:error, %{__struct__: _}} = result ->
result
{:ok, statuses} ->
statuses
|> Enum.all?(fn status -> status == @plymio_codi_status_done end)
|> case do
true ->
{:ok, {product, state}}
_ ->
state |> produce_recurse
end
end
else
{:error, %{__exception__: true}} = result -> result
end
end
@since "0.1.0"
@spec produce_codi(any, any) :: {:ok, {forms, t}} | {:error, error}
def produce_codi(opts, codi_or_opts \\ [])
def produce_codi(opts, %__MODULE__{} = state) do
# need to reset patterns to stop infinite recursion
with {:ok, %__MODULE__{} = state} <- state |> reset_patterns,
{:ok, %__MODULE__{} = state} <- state |> reset_snippets,
{:ok, %__MODULE__{} = state} <- state |> update(opts),
{:ok, {opts_patterns, %__MODULE__{} = state}} <- state |> produce,
{:ok, opzionis} <- opts_patterns |> cpo_get_patterns,
{:ok, cpo} <- opzionis |> opzioni_flatten,
{:ok, cpo} <- cpo |> cpo_put_set_struct_field(state, @plymio_codi_field_forms_edit),
{:ok, forms} <- cpo |> cpo_edit_forms do
{:ok, {forms, state}}
else
{:error, %{__exception__: true}} = result -> result
end
end
def produce_codi(opts, new_opts) do
with {:ok, %__MODULE__{} = state} <- new_opts |> new,
{:ok, _} = result <- opts |> produce_codi(state) do
result
else
{:error, %{__exception__: true}} = result -> result
end
end
defmacro reify_codi(opts \\ [], other_opts \\ []) do
module = __CALLER__.module
quote bind_quoted: [opts: opts, other_opts: other_opts, module: module] do
with {:ok, {forms, _}} <- opts |> Plymio.Codi.produce_codi(other_opts),
{:ok, forms} <- forms |> Plymio.Fontais.Form.forms_normalise() do
result =
try do
forms
|> Code.eval_quoted([], __ENV__)
|> case do
{_, _} = value ->
{:ok, value}
value ->
{:error,
%RuntimeError{message: "Code.eval_quoted failed, got: #{inspect(value)}"}}
end
rescue
error -> {:error, error}
end
{:ok,
[
{:forms, forms},
{:module, module},
{:result, result}
]}
else
{:error, %{__exception__: true} = error} -> raise error
end
end
end
[
:doc_false,
:workflow_def_produce_stages
]
|> VEKILUTIL.reify_proxies(
@codi_opts ++
[
{@plymio_fontais_key_postwalk,
fn
:produce_stage_field -> @plymio_codi_field_stage_dispatch
:PRODUCESTAGESTRUCT -> __MODULE__
x -> x
end}
]
)
defmacro __using__(_opts \\ []) do
quote do
require Plymio.Codi, as: CODI
require Plymio.Fontais.Guard
use Plymio.Fontais.Attribute
use Plymio.Codi.Attribute
end
end
end
defimpl Inspect, for: Plymio.Codi do
use Plymio.Codi.Attribute
import Plymio.Fontais.Guard,
only: [
is_value_unset: 1
]
def inspect(
%Plymio.Codi{
@plymio_codi_field_vekil => vekil,
@plymio_codi_field_snippets => snippets,
@plymio_codi_field_patterns => patterns,
@plymio_codi_field_forms => forms
},
_opts
) do
vekil_telltale =
vekil
|> case do
x when is_value_unset(x) -> nil
x -> "K=#{inspect(x)}"
end
snippets_telltale =
snippets
|> case do
x when is_value_unset(x) -> nil
x when is_list(x) -> "S=#{x |> length}"
_ -> "S=?"
end
patterns_telltale =
patterns
|> case do
x when is_value_unset(x) ->
nil
x when is_list(x) ->
[
"P=#{x |> length}/(",
x
|> Stream.take(5)
|> Stream.map(fn opts ->
opts
|> Keyword.new()
|> Keyword.get(@plymio_codi_key_pattern)
|> to_string
end)
|> Enum.join(","),
")"
]
|> Enum.join()
end
forms_telltale =
forms
|> case do
x when is_value_unset(x) ->
nil
x when is_list(x) ->
"F=#{x |> length}"
end
codi_telltale =
[
snippets_telltale,
patterns_telltale,
forms_telltale,
vekil_telltale
]
|> List.flatten()
|> Enum.reject(&is_nil/1)
|> Enum.join("; ")
"CODI(#{codi_telltale})"
end
end