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:
- The name must being with an alphabetic character ('A-Z'
or 'a-z') or an underscore ('_').
- The name must contain only alphabetic characters ('A-Z'
or 'a-z'), decimal digits ('0-9') and underscores ('_').
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:
- Each element of the command list (including the command
name) is prepared as follows:
- If the element is a constant string or constant list
it is left unchanged.
- If the element is a variable reference, then it is
replaced by the value of that variable.
- If the element is an evaluation list, then it is
replaced by the result of evaluating the contained
command.
- If the element is a string constructor, then it is
replaced by the constructed string. Note that this
means that any variable references or evaluation lists
within the string constructor will also be
evaluated.
- The interpreter locates the appropriate procedure and
invokes it, passing the evaluated arguments to it.
- 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:
- It can be passed as an argument to a procedure that can
work with opaque objects.
- An opaque object's method may be invoked.
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:
- a string
- a variable reference
- an evaluation list
- a function (see below)
All values are reduced to the most appropriate of the
following types:
- string
- integer
- floating-point value
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:
- an empty string
- the integer 0
- the floating-point value 0.0
which are all considered to be false.
The following operators are supported:
Op | Operand Type | Description |
&& | Boolean | Logical "and" |
|| | Boolean | Logical "or" |
! | Boolean | Logical "not" |
== | any | Equality |
!= | any | Inequality |
< | any | Less-than |
<= | any | Less-than-or-equal |
> | any | Greater-than |
>= | any | Greater-than-or-equal |
+ | int or float | Addition |
- | int or float | Subtraction (binary)
or negation (unary) |
* | int or
float | Multiplication |
/ | int or float | Division |
% | int | Modulus |
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:
- If either operand is a float, convert both to float
- If either operand is an int, convert both to int
- Treat both as strings
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.