Module otpcl_eval

OTPCL interpreter/evaluator.

Description

OTPCL interpreter/evaluator.

OTPCL's interpreter effectively revolves around repeatedly calling 2-arity functions ("commands"), the first argument being the actual list of arguments for that function/command, and the second being the current interpretation state (expressed as a tuple of two maps, one with all command definitions and one with all variable definitions). Each command-backing function in turn returns a tuple with a return value and an updated state.

To illustrate: when OTPCL's parser encounters the command invocation foo bar baz and sends the corresponding parse tree to the interpreter, the interpreter in turn calls {Result, NewState} = Fun([bar, baz], State) (where Fun is the value of the foo key in the first element of the State tuple, Result is the return value for that command, and NewState is the updated state).

This means it's pretty straightforward to define an OTPCL command yourself from within Erlang: simply define a 2-arity function where the first argument is a list and the second argument is a 2-element tuple of maps. A module that defines OTPCL commands can/should specify which functions in that module are "OTPCL-aware" in this fashion like so:

 -module(my_otpcl_cmds).
 -export([foo/2, bar/2, baz/2]).
 -otpcl_cmds([foo, bar, baz]).  % OTPCL-aware funs in the module

 foo([Thing], State) ->
     {ok, State}.
 bar([Thing1, Thing2], State) ->
     {{Thing1, Thing2}, State}.
 baz([Name, Val], State) ->
     otpcl_stdlib:set([Name, Val], State).

The interpreter itself is also an OTPCL-aware function in this sense (albeit with a simplification in that it does not require its first argument to be a list; it can take a parse tree directly). It can thus be invoked from within OTPCL:

 otpcl> import otpcl_eval
 {ok,otpcl_eval}
 otpcl> eval {set foo "howdy~n"}
 ok
 otpcl> print $foo
 howdy
 ok
 otpcl> import otpcl_env
 ok
 otpcl> eval {
   ...> set foo "aloha~n"
   ...> print $foo
   ...> } [default_state]
 aloha
 [ ... pile of interpreter state ... ]
 otpcl> print $foo
 howdy
 ok

In fact, most OTPCL features are in turn implemented as OTPCL-aware command-backing functions; that is: OTPCL exposes its own functionality as OTPCL commands wherever it's possible/practical to do so.

Of course, one may also do this from any OTP application that uses OTPCL, e.g. one written in Erlang:

 erl> State0 = otpcl_env:default_state().
 [ ... pile of interpreter state ... ]
 erl> {ok, State1} = otpcl_stdlib:set([foo, <<"howdy~n">>], State0).
 [ ... pile of interpreter state ... ]
 erl> {ok, State2} = otpcl_eval:eval("print $foo", State1).
 howdy
 [ ... pile of interpreter state ... ]

Data Types

column_no()

column_no() = integer()

eval_error()

eval_error() = {error, reason(), state()}

eval_input()

eval_input() = string() | binary() | [token()]

eval_success()

eval_success() = {ok, state()}

filename()

filename() = any()

funs()

funs() = map()

level()

level() = atom()

line_no()

line_no() = integer()

position()

position() = {filename(), line_no(), column_no()}

reason()

reason() = atom() | {atom(), any()}

state()

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

token()

token() = {char(), position()}

tree()

tree() = {parsed, level(), [tree()] | [token()]}

vars()

vars() = map()

Function Index

eval/1Evaluate a string with the default OTPCL starting state.
eval/2Evaluate a string with a custom starting state.
eval_file/1Evaluate the named file with the default OTPCL starting state.
eval_file/2Evaluate the named file with a custom starting state.
interpret/1Interpret the parse nodes with the default OTPCL starting state.
interpret/2Interpret the parse nodes with a custom starting state.
make_atom/1Extract an atom from a token string.
make_atomic/1Extract a float, integer, or atom (in order of preference) from a token string.
make_binstring/1Extract a binary string from a token string.
make_charstring/1Extract a character string from a token string.

Function Details

eval/1

eval(Src::eval_input()) -> eval_success() | eval_error()

Evaluate a string with the default OTPCL starting state.

eval/2

eval(Src::eval_input(), State::state()) -> eval_success() | eval_error()

Evaluate a string with a custom starting state.

eval_file/1

eval_file(Filename::filename()) -> eval_success() | eval_error()

Evaluate the named file with the default OTPCL starting state.

eval_file/2

eval_file(Filename::filename(), State::state()) -> eval_success() | eval_error()

Evaluate the named file with a custom starting state.

interpret/1

interpret(Nodes::tree() | [tree()]) -> eval_success() | eval_error()

Interpret the parse nodes with the default OTPCL starting state.

interpret/2

interpret(InvalidNode::tree() | [tree()], State::state()) -> eval_success() | eval_error()

Interpret the parse nodes with a custom starting state.

make_atom/1

make_atom(Tokens::[token()]) -> atom()

Extract an atom from a token string. This skips any attempt to check if an atom is a number (which means single-quoted atoms might technically be more efficient than unquoted atoms at the moment...).

make_atomic/1

make_atomic(Tokens::[token()]) -> atom() | integer() | float()

Extract a float, integer, or atom (in order of preference) from a token string.

make_binstring/1

make_binstring(Tokens::[token()]) -> binary()

Extract a binary string from a token string.

make_charstring/1

make_charstring(Tokens::[token()]) -> string()

Extract a character string from a token string.


Generated by EDoc