BlueScript: A Quick Introduction


Return to index

Basic Elements

Strings

The fundamental unit of BlueScript is the string. A string that does not contain spaces or special characters (defined later) can be represented without any special treatment. For example:

Hello
represents the string "Hello".

A string generally ends at the first white-space character. If you wish to include whitespace in a string, you can use the escape character '\' to force BlueScript to treat the white-space character as being "non-special". For example:

Hello\ World!
represents the string "Hello World!".

White-space can also be included in a string using quoting. There different forms of quoting. Given these examples:

"Hello World!" {Hello World!}
Both of these examples represent the string "Hello World!". There are side-effects to using quotes which are described below.

A string that is specified without quotes is also referred to as a constant string or static string. For example, the following examples:

Hello Hello\ World
are constant strings.

Integers

Sometimes strings are interpreted as integers. Integers may be represented by any of the standard C forms, e.g. decimal

123510, -15
or hexadecimal (if preceded by "0x" or "0X")
0x1234, 0X5abC3f
or octal (if preceded by "0")
0177, 0253

Floating-Point

Sometimes strings are interpreted as floating-point numbers. Floating-point numbers may be represented by any of the standard C forms, e.g.

1.1023, 6.0e10, -4.123823E-5

Lists

Any string can be interpreted as a list. The elements of a list are assumed to be separated by white-space. For example:

"Hello there   world!"
can be interpreted as a list with three elements: "Hello", "there" and "world!". Note that there can be any number of white-space characters between elements of a list; extra white-space characters are ignored.

To define more complex lists, or to include elements in the list that contain white-space, we can use list quoting operators. For example, the following:

{Hello there   world!}
represents the same list: "Hello", "there" and "world!". However, unlike other operators, we can use the list quoting operator to nest lists. For example, the following:
{Hello there {} world!}
is a list with four elements: "Hello", "there", "" (an empty string) and "world!". A more complex example:
{{This is the first element} {This is the second} {And third!}}
shows a list of three elements, where each element of the list can also be interpreted as a list.

Lists defined with list quotes are referred to as constant lists or static lists. Any list can also be considered as a string. The string representation of a list is generated by concatenating the elements of a string together with a single space character in between each element.

Variables

So far, everything we have described has been static. The BlueScript environment also defines variables which (as in other languages) are objects that contain values. We can specify the the value of a string is not a static value, but is instead the value contained in a variable using the '$' character. For example, the value of the following string:

$holder
is the contents of the variable called "holder". Using the syntax, the variable name must satisfy the following:

An alternate syntax uses the '{' and '}' quotes to surround the name of the variable, for example:

${holder}
has the same meaning as the previous example. This syntax does not limit the types of variable names that can be created.

Anywhere we can use a string, we can generally replace it with a variable reference. However, we cannot replace a substring with a variable reference without using a string constructor (see below). For example, the following:

${var}string
is illegal on its own. It may be made valid by using the string constructor quotes. For example, the following:
"${var}string"
is legal. See the discussion below on string constructors for more detail.

Commands

BlueScript code (referred to as a script) is a sequence of commands. A command is an unquoted list then ends with a newline character. For example:

cmdname arg1 arg2 arg3
This would invoke the procedure "cmdname" with three arguments "arg1", "arg2" and "arg3".

A command may span multiple lines if the newline character is either escaped (using the '\' character) or is contained in quotes (e.g. '""' or '{}'). For example:

foreach x {1 2 3} { set y $x set z [expr $y + $y] }
is a single command even though it is spread across four lines.

Evaluation Lists

The evaluation quotes ('[' and ']') specify a list that is to be treated like a command. When it is evaluation, an evaluation list is replaced with the result of executing a command. For example, given:

cmdname [foo bar] x
would call the command "cmdname" with two arguments. The first argument would be the result of evaluating the command "foo" with the argument "bar" and the second argument to "cmdname" would be "x".

String Constructors

The string quotes ('"') are actually string constructors. That is, they allow the substitution of variable references and evaluation lists to construct strings. For example, the following:

"Hello there, ${joe}. How do you like [gethostname]?"
will evaluate to a string, but "${joe}" will be replaced with the value of the variable "joe" and "[gethostname]" will be replaced with the result of evaluating the procedure "gethostname".

Evaluating a Command

A command is evaluated as follows:

  1. Each element of the command list (including the command name) is prepared as follows:
  2. The interpreter locates the appropriate procedure and invokes it, passing the evaluated arguments to it.
  3. Upon completion, a procedure generates a result (which is left in the interpreter's result buffer) or generates an error. An error causes an exception, which interrupts execution of the script.

When evaluating a command its arguments are passed as values. For example, after executing the following code:

proc square {x} { set x [expr $x * $x] return $x } set x 10 set y [square $x]
The value of "$x" will be "10" and the value of "$y" will be 100. The procedure square does not modify the value of "x" that is passed to it.

There is an important exception to the "pass-by-value" rule which involves opaque objects (see below).

Opaque Objects

Since BlueScript is meant to be an embedded scripting language it needs to be able to interact with and manipulate objects which many not be easily represented by any of the above models. To this end, BlueScript can handle opaque objects. As the name implies, an opaque object is one that BlueScript knows nothing about it. That is, it cannot be completely represented as a literal value (i.e. as a string). Thus it cannot be passed around as a value. Instead, an opaque object is passed around as a reference.

A reference to an opaque object is always contained in a variable. For example, there are standard functions in BlueScript that represent files and other data sources and sinks as streams. (See the "Standard BlueScript Reference" for more details on streams and stream functions.) An optional procedure "stdout" returns a reference to stream corresponding to the standard output. For example:

set x [stdout]
would store a reference to the standard output stream object in the variable "x".

An opaque object can be manipulated in one of two ways:

A method is a procedure that is associated with an opaque object itself. This is a simplistic form of object-oriented programming. If an opaque object supports methods, then the opaque object reference can itself be used as a command name, which should then be followed by the name of the method and any arguments to the method.

Methods are easier to understand by example. A stream object implements a number of methods, including one called "writeln". This method takes one argument which is interpreted as a string and then written to the given stream followed by a new-line character. For example, the following:

[stdout] writeln "Hello, World!"
would write the string "Hello, World!" followed by a new-line to the stdout stream. Since we can store a reference in a variable, we could also code this as:
set x [stdout] $x writeln "Hello, World!"

Note that opaque objects are always represented as references. So if we were to copy a stream object as follows:

set x [stdout] set y $x
then the variables "x" and "y" both refer to the same stream object, since what is stored in "y" is a copy of the reference that is stored in "x".

This "pass-by-reference" behaviour for opaque objects is also used when an opaque object is an argument to a command. For example, in the following:

proc write_hello {s} { $s writeln "Hello, World!" } write_hello [stdout]
The "stdout" stream is passed as a reference to the "write_hello" command. This means that the variable "s" in the "write_hello" command refers to same object as the result of "[stdout]".

Expressions

It is a common case for commands to make use of infix mathematical or logical expressions. To this end, BlueScript includes a common expression engine.

Expressions use values as operands. A value can be represented as:

All values are reduced to the most appropriate of the following types: At times it is useful to interpret a value as a Boolean true-or-false value. In these cases, all possible values are considered to be "true" except for the following: which are all considered to be false.

The following operators are supported:

OpOperand TypeDescription
&&BooleanLogical "and"
||BooleanLogical "or"
!BooleanLogical "not"
==anyEquality
!=anyInequality
<anyLess-than
<=anyLess-than-or-equal
>anyGreater-than
>=anyGreater-than-or-equal
+int or floatAddition
-int or floatSubtraction (binary) or negation (unary)
*int or floatMultiplication
/int or floatDivision
%intModulus

Operator precedence is the same as in Standard C. In addition, parentheses ("(" and ")") can be used to group together sub-expressions and override precedence.

When evaluating an operator, the expression engine always attempts to make the types of both operands correspond. If the operator has no specific requirements, then the following steps are taken:

Functions may be used to force a value to be a particular type (see the second on function below).

Functions

There are a special set of functions that may be used in expressions. A function takes 0 or more arguments. The following arguments are currently defined:

int(x)
Force the value x to be interpreted as an int. If it cannot, then an error is generated.
float(x)
Force the value x to be interpreted as a float. If it cannot, then an error is generated.
string(x)
Force the value x to be interpreted as a string.
boolean(x)
Convert the given value to the integer "0" if it is a boolean false value, or the integer "1" otherwise.