Binder Shell Syntax

< Binder Shell Data | Binder Kit | Binder Terminology >

This page provides a more detailed reference on the syntax and capabilities of the Binder shell.

The Binder Shell is a basic implementation of the POSIX shell syntax (spec at http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html) with a few extensions. While it should be able to parse the full POSIX grammar correctly, there are a few features, most notably pipes, that aren't implemented yet.

Besides these limitations, the shell provides the same general environment one expects from a POSIX shell:

variable="something"

if [ "$variable" -eq "something" ]
    echo "Variable is something"
else
    echo "Variable is something else"
fi

For the rest of this document we will assume that you are already familiar (as much as you want to be) with POSIX shell syntax.

Binder Shell Extensions

The Binder Shell introduces a few extensions to standard POSIX shell that make it much more useful in the Binder environment. Most of these are semantic changes, though there are a few important new grammatical constructs.

All environment variables, command arguments, and return codes are SValues

This means that most data handled by the shell is typed, not just a simple string. The arguments to a function, its return code, and environment variables in the shell can contain strings, integers, flattened types (rect, point, etc), or even references to objects or complex mappings.

As these values propagate between the command and the shell, their type is propagated as well. For example, if you have an environment variable SOMETHING that contains a reference to an IBinder object, you can pass it to a function like a normal environment variable:

inspect $SOMETHING

The second argument that the inspect command receives will be a SValue containing a pointer to the same binder. The command can similarly return a result SValue containing an object that the shell can use.

New syntax $[cmd ...] for retrieving the result of a command

The standard POSIX shell defines the syntax $(cmd ...) to embed the output of a command into the place this construct appears. The Binder Shell adds a variant $[cmd ...], which embeds the result of a command. Because command results are now an SValue, this allows you to propagate typed data through the shell.

For example, there is a lookup command that returns the SValue of a particular property in the context. This can then be assigned to an environment variable:

SURFACE=$[lookup /services/surface]

The environment variable can be passed to another command:

put $SURFACE show_updates true

One could even write commands that take typed data as input and generate a typed result. For example, if we had two theoretical commands, rect and point, which generate SValues containing data of their respective types, we could write shell code like this:

RECT=$[rect 0 0 100 120]
POINT=$[point 10 10]

NEWRECT=$[rect_offset $RECT $POINT]

Or even:

NEWRECT=$[rect_offset $RECT $[point 10 10]]

This facility is used extensively by the standard commands for working with the Binder runtime, such as new, new_process, and invoke.

New syntax @{ key->value, ... } for building complex values

The Binder Shell also adds a new construct for conveniently building up basic SValue types. The text inside a @{ ... } section defines SValue mappings (separated by ->) and sets (separated by ,); a combination of both can be used to create multiple mappings. Some examples:

@{ data }                       # A simple string
@{ something, somethingelse }   # A set of strings
@{ param->value }               # A mapping
@{ {param->value}[param] }      # Lookup in a mapping
@{ param1->something,           # Multiple mappings
   param2->somethingelse }
@{ param1->{ value1, value2 } } # Mapping to a set
@{ param1->{ nested->value } }  # Mapping to a mapping
@{param1->{nested->value}}      # All spaces are optional and ignored

Tokens inside of an SValue context are typed. If the token is all numbers, it is interpreted as an integer; if it is all numbers with a single period, it is a float; true and false are the corresponding boolean values; otherwise, it is a string:

@{ 1 }                          # An integer
@{ [abcd] }                     # An integer of ASCII characters
@{ 1.0 }                        # A float
@{ true }                       # Boolean truth
@{ 1->something }               # Integer mapped to string

You can also explicitly specify the type of a token. If a token is enclosed in double quotes, it is always converted to a string. If you prefix it with (), you can force it to one of the fundamental types: (int32), (float), (string), (bool):

@{ "1" }                        # A string
@{ (string)1.0 }                # Also a string
@{ (int64_t)10 }                # A 64 bit integer
@{ (nsecs_t)123456 }            # A time
@{ (float)1 }                   # A floating point number
@{ (int32_t)$VAR }              # Cast to an integer
@{ (bool)1 }                    # Boolean truth
@{ "true" }                     # The string "true"

Finally, environment variables and command results can be used as tokens:

$ SURFACE=$[lookup /services/surface]

$ M1=@{ 0->$SURFACE }           # Integer mapped to an object
$ M1=@{ 0->$[lookup /services/surface] }    # Equivalent
$ M2=@{ a->$M1, b->"foo" }      # Make set of mappings
$ M=@{ $M1 + $M2 }              # Combine the mappings
$ V=@{ $M[0] }                  # Look up a value in a mapping

See Binder Shell Data for more examples.

Function invocation with $OBJECT.Function()

You can append a '.' to an environment variable name in order to perform a function invocation if that variable holds an object.

$ E=$[inspect /services/surface org.openbinder.services.IErrAlert]
$ RESULT=$E.ShowAlert("Alert text")

The arguments are supplied as a comma-separated list, and are parsed as a normal command line: plain text will be interpreted as strings, you can use $ for variables, $[] to run commands, @{} to build typed values, etc.

New foreach control structure

In addition to the standard for control structures, the Binder Shell includes a foreach statement for operating on IIterable and IIterator objects, and SValue mappings. The general syntax is:

foreach [key] value [in|over] data [data ... ]; do
	statements
done

If key is not specified, then value will contain {key->value} mappings for each item. The data items can be variables or other constructs.

The foreach ... in ... form allows you to operate on iterators the data you supply must be either an IIterable or IIterator object, or a path to an interable object in the namespace, or a mapping containing values that are iterables or paths. For example, to iterate over all items in /services, you would write this:

foreach key value in /services; do
    echo $key is $value
done

Resulting in:

informant is SValue(sptr<IBinder>(0x80967c4 9Informant))
memory_dealer is SValue(sptr<IBinder>(0x8090f34 13BMemoryDealer))
tokens is SValue(sptr<IBinder>(0x809a13c 2TS))

The foreach ... over ... form allows you to operate on value mappings it will simply decompose the data into its separate mappings. For example:

foreach k v over @{0->1, 2->3, 1->a} string $[lookup /services/informant]; do
    echo $k is $v
done

Results in:

0 is 1
1 is a
2 is 3
SValue(wild) is string
SValue(wild) is SValue(sptr<IBinder>(0x8096f74 9Informant))

This is a good example of why SValue mappings are defined the way they are, where a simple value V is formally the mapping {wild->V}. Notice this coming into play for the last two items, which are not normally considered to be mappings.

Also notice a special property of SValue ordering related to integers. The order that SValue holds its sets in is not defined to be anything useful, except in the case of integer keys: these will be in their natural order. This property is convenient in dealing with sets of mappings of integer keys representing arrays.