Module otpcl_meta

OTPCL meta-commands.

Description

OTPCL meta-commands. These commands all pertain to modifying the OTPCL interpreter's execution state/environment from within an OTPCL program; if you intend for your OTPCL-based DSL or what have you to be Turing-complete, this would be the module to either import or reimplement (and likewise, if you don't want your OTPCL-based DSL or what have you to be Turing-complete - e.g. for restricted/safe configuration files - this would be the module to exclude).

Data Types

funs()

funs() = map()

state()

state() = {funs(), vars()}

vars()

vars() = map()

Function Index

apply/2Executes the specified command or function with the given arguments (if any).
cmd/2Gets or sets the definition for the given command.
get/2Get the value of the named variable.
import/2Imports commands from an Erlang module.
set/2Set the value of the named variable.
subcmd/2Returns a subcommand dispatcher.
use/2Creates a command representing a module.

Function Details

apply/2

apply(Args, State) -> any()

Executes the specified command or function with the given arguments (if any). If a function, assumes it's able to operate as an OTPCL command (that is: it's a 2-arity function that takes a list of arguments and a state). If pure precedes the function, instead assumes that the function is meant to be an ordinary Erlang function and is "wrapped" (i.e. the input state and output state are identical, aside from a different $RETVAL).

cmd/2

cmd(Args, State) -> any()

Gets or sets the definition for the given command. First argument is the command name. Second argument is either a function (i.e. the kind produced via fun in Erlang or OTPCL; this function should be a 2-arity function accepting a list of arguments and a 2-element tuple of maps) or the argument list for the first of one or more pairs of argument lists and command bodies. Like Erlang functions, OTPCL commands support multiple definitions via pattern matching; unlike Erlang functions, they lack a concept of "arity", and also do not currently support guards (though this will hopefully be fixed in future versions of OTPCL).

If no argument is passed to cmd after the command name, cmd will instead return the Erlang function backing that command.

get/2

get(X1, X2) -> any()

Get the value of the named variable. Mostly useless from within OTPCL, but quite handy when manipulating OTPCL states from within Erlang or some other situation external to OTPCL.

import/2

import(X1::[atom(), ...], State::state()) -> {ok, state()}

Imports commands from an Erlang module. Will import either all commands (if only a module name is provided) or specifically-named commands (if any are passed after the module name). If the module includes an -otpcl_cmds attribute with a list of command names (corresponding to 2-arity functions in that module), OTPCL will import these functions (and only these functions) as OTPCL commands outright (that is: it will assume that the module has such-named 2-arity functions exported/defined, and that those functions each accept a parameter list + state and return a tuple with a return value + state); else, OTPCL will "wrap" each imported function in a command that simply calls that function with the provided arguments and returns the result (without touching the input state).

Either mode of operation can be forced by passing either otpcl or erlang (respectively) before the module name. Note that otpcl is the default for importing a whole module, while erlang is the default for importing specific functions. Also note that OTPCL doesn't really have a concept of "arity" (at least in the "foo/1 and foo/2 are different functions" sense), so if your module foo defines bar/1 and bar/2, import foo bar will create a bar command that wraps both.

To summarize:

 import foo                # imports everything in module foo
 import foo bar baz        # imports bar and baz from foo
 import otpcl foo bar baz  # forcibly treats bar and baz as OTPCL commands
 import erlang foo bar baz # forcibly treats bar and baz as Erlang functions
It's usually preferable to choose use over import, since use avoids namespace clashes. Both mechanisms are provided, though, for those who prefer brevity.

set/2

set(X1, X2) -> any()

Set the value of the named variable.

subcmd/2

subcmd(Args, State) -> any()

Returns a subcommand dispatcher. The resulting function (when set as a command) will treat the first argument as a subcommand name, look it up against an internal dictionary of subcommand names, and execute the corresponding subcommand function.

Note that this is not strictly necessary in order to implement commands that use the subcommand pattern; OTPCL, like any good child of Erlang, will happily let you do the same thing ahead-of-time by allowing you to specify multiple argument specs and pattern match against the subcommand names. subcmd is more intended for dynamic generation of subcommand dispatchers (e.g. for the use command in this very module). There's certainly nothing stopping you from using subcmd instead of / in addition to ahead-of-time pattern matching, though.

use/2

use(X1, State) -> any()

Creates a command representing a module. The generated command will dispatch subcommands against the list of exported functions in the module (i.e. each function becomes a subcommand of the final command). To summarize:

 use foo         # create command foo with foo's funs as subcommands
 use foo as bar  # create command bar with foo's funs as subcommands
 use otpcl foo   # forcibly treat all subcommand funs as OTPCL-aware
 use erlang foo  # forcibly treat all subcommand funs as non-OTPCL-aware


Generated by EDoc