AdaScript is intended to be "upward compatible" with Ada. AdaScript
scripts should run with little difficulty under Ada, but Ada programs may
require large changes run under BUSH.
Ada is case-insensitive and programs may need to have the capitalization
of keywords changed to fit the case expected by AdaScript.
abort
abs abstract accept aliased all and array at begin body case clear constant declare delay delta digits do |
else
elsif end entry env exception exit for function generic goto help if in is jobs limited logout loop |
mod
new not null of or others out package pragma private procedure protected raise range record rem renames requeue |
return
reverse select separate subtype tagged task terminate then trace type typeset unset until use when while with xor |
If you attempt to use a reserved word, you will receive a error
=> digits : integer
digits : integer;
^ identifier expected, not a keyword
=> DIGITS : integer
=>
All Ada keywords are also reserved, even those that are not used by
AdaScript, to make it easier to compile scripts under GCC Ada.
=> null; # A Bourne shell style comment
=> null; -- An Ada style comment
Characters are enclosed in single quotes.
Strings are enclosed in double quotes.
Universal Types
There are three "universal types":
Type Name | Content | Usage |
universal_string | unlimited length, 8-bit characters | text |
universal_numeric | double precision floating point values | numbers |
universal_typeless | same as universal_string/numeric | text or numbers |
The first two types form the basis for all other AdaScript string and numeric types. Variables declared as universal_typeless change their type between universal_string and universal_numeric depending how they are used. If AdaScript cannot decide in a particular context, the variable type defaults to universal_string. Typeless variables correspond to variables in Bourne shells and are provided for as a command line convenience.
Universal types automatically match any type derived from the same universal type. A universal_numeric variable accepts integer or floating point values. A universal_string variable accepts single characters or strings containing many characters.
Universal types are used for all AdaScript literals. For example, a string literal like "hello" is a universal_string and be assigned to any string type. The numeric literal 45.5 is a universal_numeric can be used with float, long_float, or any other numeric type.
Using these three built-in types will give you a minimum amount of type checking, suitable for short scripts or quick command line calculations. Universal types should not be used in large scripts because they will greatly reduce the number of errors BUSH can detect.
Predefined, Non-Universal Types
For more extensive scripts, AdaScript extends the universal string and
numeric types into all the predefined Ada language types, plus some AdaScript-specific
types:
Type Name | Base Type | Usage | GCC Ada Equivalent |
integer | universal_numeric | number without a radix point | integer |
natural | universal_numeric | 0 or integer larger than zero | natural |
positive | universal_numeric | integer larger than zero | positive |
short_short_integer | universal_numeric | very small integer | short_short_integer |
short_integer | universal_numeric | small integer | long_integer |
long_integer | universal_numeric | large integer | long_long_integer |
long_long_integer | universal_numeric | very large integer | float |
float | universal_numeric | floating point number | float |
short_float | universal_numeric | small floating point number | short_float |
long_float | universal_numeric | large floating point number | long_float |
character | universal_string | 8-bit character | character |
string | universal_string | unlimited length string | almost unbounded_string |
unbounded_string | universal_string | unlimited length string | almost unbounded_string |
duration | universal_numeric | time, float seconds | duration |
boolean | enumerated type | true or false | boolean |
file_type | limited type | operating system files | file_type |
file_mode | enumerated type | in_file, out_file or append_file | file_mode |
command | limited type | alias for an operating system command | - |
The built-in packages may define additional types.
By default, all numeric variables are initialized without any value. Any attempt to use uninitialized numeric variables in an expression will cause an error or exception.
=> i : integer -- no value specified
=> i := i + 1
i := i + 1;
^ exception
raised
All types are logical types: that is, all numeric types are stored in the same format. A natural, integer or float are all stored as a universal numeric value. There are only minimal checks to make sure that variables of these types conform to their descriptions. However, types provide an indication to the reader of how a variable is intended to be used, and AdaScript will not allow these types to be combined without an appropriate type cast.
=> i : integer := 5
=> f : float := 0
=> f := i
f := i;
^ type 'float' is not compatible
with type 'integer'
=> f := float(i) -- typecast
=> ? f
5
You cannot typecast a numeric type into a string type directly. There are functions in the numerics and strings packages to do these conversions.
Since all values are stored as a universal type, this can cause some unusual side-effects. A character variable can contain more than one character if you really want it to by assigning a string literal. Characters are stored as a universal_string and a string literal is a universal_string type. AdaScript will allow the assignment. However, the type checking will prevent a character variable from being assigned to a string variable.
c : character;
c := "hello"; -- confusing, perhaps stupid, but legal
s : string := c; -- ILLEGAL
AdaScript strings are an unbounded string type--that is, they are stored as an Ada.Strings.Unbounded.Unbounded_String variable. They have an unlimited length and are not implemented as any sort of array. Unlike Ada "fixed" strings, AdaScript strings can have any length and are not subject to array restrictions.
Constants
Constants can be declared with the word "constant" for any type. The use of "constant" doesn't not affect the type of the variable--it simply prevents new values from being assigned by making the variable "read-only".
program_name : constant string := "Nightly FTP Transfer";
Limited Types
file_type and socket_type variables are known as limited type variables. Limited types cannot be assigned a new value with an assignment statement
=> f : file_type
=> g : file_type
=> f := g
f := g;
^ limited variables cannot be assigned
a value
BUSH manages the contents of these variables and scripts are not allowed to change the contents.
Command Types
External operating system commands can be declared using command variables. When a command is declared, BUSH will ensure that the command exists and is runnable.
Command types are similar to limited types and have several restrictions.
=> l : constant command := "/bin/ls"
=> m : constant command := "/bin/lt"
m : constant command := "/bin/lt";
^ "/bin/lt" is not an executable command
=> n : constant command := l;
n : constant command := l;
^ type universal_string is inherently different from a command
=> ? l & " is the path"
? l & " is the path";
^ type command is inherently different from a universal_string
=> ? l
/bin/ls
The subtype statement will create a type that is compatible with the original, as if it was a renaming of the original type.
=> subtype int is integer;
=> i1 : integer := 1
=> i2 : int := 2
=> ? i1 + i2
3
In this case, "int" is equivalent to "integer" and variables of both types can be mixed freely without type casting. Unlike Ada 95, there is no way to place restrictions on a subtype--they are simple renamings in AdaScript.
To make incompatible types, you need to create a new type with the type statement.
=> type employee_number is new integer;
=> type customer_number is new integer;
=> en : employee_number
=> cn : customer_number
=> en := cn
en := cn;
^ type 'employee_number'
is not compatible with type 'customer_number'
In this case, "employee_number" variables cannot be mixed with "customer_number" (or other) variables without a typecast. Use new types to make sure variables that are logically different don't accidently mix.
=> type fruit is (apple, blueberry, cherry);
=> f : fruit
=> f := apple
=> f := 5
f := 5;
^ type fruit (an enumerated type)
is inherently different from a universal_numeric
There are two built-in enumerated types. The boolean type is a predefined enumerated type with values "false" and "true". The file_mode type has the values "in_file", "out_file" and "append_file".
AdaScript has no aggreagate types. There is no object, array or record/structure
type. If you need these, your project is probably too complicated for a
simple script and should be upgraded to Ada 95.
To declare an anonymous array (an array with no type name):
=> zerbra_population : array(1900..1999) of natural
=> type divisions is (america, asia, africa, eurpoe, oceania )
=> sales : array (america..oceania) of float
This array contains 100 entries and each entry is a natural number. To assign values or to access array entries, put the index number in parentheses after the array name.
=> zebra_population(1950) := 150000
=> ? zebra_population( 1950 )
150000
Attempting to use an out-of-range index number is an error
=> ? zebra_population( 0 )
^ exception raised
You can create new array types.
=> type zebra_list is array( 1900..1999 ) of natural;
=> zl : zebra_list
When you declare an array, you can assign a list of initial values or copy the values of another identical array.
=> type grocery_list is array(1..10) of string
=> gl : grocery_list := ( "milk", "bananas", "bread", "butter",
"salt", "flour", "pizza", "noodles", "", "" )
=> gl2 : grocery_list := gl
=> ? gl2(2)
bananas
An empty array can be created using 1..0. This is the only case where the low bound is higher than the high bound.
=> empty : array(1..0) of integer
Bush does not support assigning one array to another in an assignment
statement, unconstrained arrays or multi-dimensional arrays.
Assignment (:=) is a statement, not an operator, and cannot be used in expressions.
=> x := 5 * ( 7 + 2 );
=> s := "hello " & "there!";
"in" and "not in" test for membership in a range. (In Ada, the range can be a type but under AdaScript types have no bounds.) The range can be an pair of numbers or a pair of enumerated items.
=> b := green in red..blue;
=> b := 5 not in 10..20;
=> total := @ + 1; -- total := total + 1;
(An operand is used instead of C-style "+=", "-=", and so forth because it's much more resilient to typos. Leaving out the "@" or transposing it with the ":=" or "+" will result in a syntax error. In C, these mistakes usually result in legal assignments.)
When assigning a value to an array, @ refers to the array item being assigned, not the entire array.
=> zebra_population( 1966 ) := @+1; -- add 1 to 1966 population
AdaScript provides a last output operand. "%", pronounced "last output", returns the last put_line value. This is similar to Python's last output operand.
=> put_line( 5*2 )
10
=> put_line( %+5 )
15
The type of the last output is remembered.
=> put_line( 5 )
5
=> put_line( % & " is a good number" )
put_line( % & " is a good number" );
^ type universal_numeric is inherently different from a universal_string
The Bourne shell form are intended as command line shortcuts and the command_line package should normally be used in a well-structured script.
rm ("/tmp/temp." & $$)
if $? /= 0 then
put_line( standard_error, "unable to delete temp file"
);
end if;
The status code of the last command executed is returned from a script
when it finishes executing. A specific status code can be returned
using the command_line package.
=> ls > list_output.txt 2> list_errors.txt
The redirect operands are considered to be a command line convenience. More powerful redirection is possible using the Text_IO package.
Command pipelines are created by connecting one or more commands using the pipe (|) symbol.
=> ls | grep ".txt"
The result from a command pipeline is the result of the last command
in the pipeline. Pipelines can only have one input redirection (for
the first command), one output redirection and one error redirection (for
the final command). Pipelines cannot be run in the background using
&.
if statements are used for conditional branching.
if x > y then
put_line( "x is greater than y" );
elsif x = y then
put_line( x is equal to y" );
else
put_line( x is less than y" );
end if;
The case statement can test a variable for several different values.
type country is ( australia, u_k, brazil );
...
case c is
when austraila =>
put_line( "Australia" );
when u_k =>
put_line( "United Kingdom" );
when brazil =>
put_line( "Brazil" );
when others =>
put_line( "Unexpected country" );
end case;
The "when" cases must not be variables. The "when others" case is always required.
The while loop is a pre-test loop. The commands in the loop are repeat while the condition is true and the condition is tested each time the first line of the loop is executed.
while x > y loop
x := @ + 1;
end loop;
The for loop increments its index variable by 1 until it iterates through the specified range. The index variable is automatically declared for you and only exists for the scope of the the loop. The range can either be numeric or enumerated.
for i in 1..10 loop
put( "i is " );
put_line( i );
end loop;
To loop in reverse in a for loop, use "in reverse" instead of "in".
Any loop can be exited by using either an exit statement or an "exit when" shorthand.
if x > 100 then
exit;
end if;
exit when x > 100;
A "loop" loop is a general purpose loop. It can only be exited with "exit".
loop
reply := get_line;
exit when reply = "exit";
end loop;
null; -- do nothing
delay 2.5; -- wait 2 1/2 seconds
system( "date" ); -- execute the Linux date command
return; -- quit the program
=> echo
will run the Linux echo command and print a blank line to the screen, the same as new_line.
Commands are accepted in one of two different formats. If the command is followed by a "(", the parameters are expected to be in AdaScript format with each parameter separated by a comma (","). These parameters may be any legitimate AdaScript expression and no shell quote removal or file globbing is performed.
=> ls( "bush.adb" )
bush.adb
If the command is not followed by a "(", the parameters are expected to be in Bourne shell format. This is provided for convenience in interactive sessions. The parameters are shell "words" separated by spaces. Each word has file globbing performed. The words may be enclosed in double quotes to allow embedded spaces, or single quotes to inhibit file globbing. Special characters may also be escaped with backslashes.
=> ls b*.adb
builtins.adb bush.adb
Bush will not perform any BASH-style "$" substitutions.
Command names containing space characters can be quoted with double quotes.
=> "inventory report"
When pragma ada_95 is used, shell commands must only use the AdaScript parameter format, to make conversion to Ada 95 easier.
External commands can be run in the background using an ampersand ("&") at the end of the command. With AdaScript parameters, place the ampersand after the closing parenthesis. The jobs command displays the status of any outstanding background commands.
The built-in shell commands are listed in a section above. when a Linux command conflicts with a built-in command, the Linux command can be executed using the command command.
The results of a command can be captured as a string using backquotes. The commands should be ended with a semi-colon. Commands appearing in backquotes will be syntax checked along with the rest of the commands in a script.
=> date : string := `date;`
If there is a trailing line feed (or carriage return/line feed for Windows) it will be removed.
Standard input, standard error and standard output can be redirected
using the Text_IO package.
begin
see declare
case
Syntax: case var is when constant|literal => ... when others => ...
end case
Description: Test a variable for multiple values. "when others" case
is required.
cd
Syntax: cd - | dirname
Description: change directory. "-" is the previous directory.
A leading '~' is your home directory.
clear
Syntax: clear
Description: reset tty device and clear the screen
close
Syntax: close( file )
Description: close an open file
command
Syntax: command cmd
Description: run a Linux command (instead of a built-in command).
create
Syntax: create( file [, out_file | append_file] [, path ] )
Description: create - create a new file or overwrite an existing file.
The default type is out_file. The default path a temporary file name.
declare
Syntax: [declare declarations] begin ... end
Description: begin a new block
delay
Syntax: delay secs
Description: wait (sleep) for a specific time
delete
Syntax: delete( file )
Description: close and delete a file
end_of_file
Syntax: end_of_file( file )
Description: true if an in_file file has no more data
end_of_line
Syntax: end_of_line( file )
Description: true if an in_file file has reached the end of a line
with get
else
see if
elsif
see if
env [ident or keyword]
Syntax: env
Description: show all identifiers, or identify an identifier or keyword.
exit
Syntax: exit | exit when condition
Description: break out of a loop
for
Syntax: for var in [reverse] first..last loop ... end loop
Description: for loop - loop through between first and last assigning
value to var. The for starts a new block and the for variable is automatically
declared based on the type of first.
get
Syntax: get( [file,] var )
Description: read a character from a line of text.
get_line
Syntax: var := get_line [ (file) ]
Description: read a line of text
if
Syntax: if expression then ... [elsif expr then ...] [ else ...]
Description: conditional execution";
inkey
Syntax: c := inkey
Description: read a character from standard input without echoing
is_open
Syntax: is_open( file )
Description: true if file is open
jobs
Syntax: jobs
Description: list status of current background jobs
line
Syntax: line( file )
Description: the number of read/written lines
logout
Syntax: logout
Description: terminate an interactive login session
loop
syntax: loop ... end loop
Description: General loop. exit with an exit statement.
mode
Syntax: mode( file )
Description: the file mode (in_file, out_file, append_file)
name
Syntax: name( file )
Description: name of an open file
new_line
Syntax: new_line [(file)]
Description: start a new line
null
Syntax: null
Description: do nothing
open
Syntax: open( file, in_file | out_file | append_file, path )
Description: open an existing file or open a socket
pragma
interpreter directive
put
Syntax: put ( [file], expression [, picture] )
Description: write to output, no new line. If picture is included,
format the number according to the picture.
put_line
Syntax: put_line ( [file], expression )
Display: write to output and start new line
pwd
Syntax: pwd
Description: present working directory
reset
Syntax: reset( file [,mode]
Description: reopen a file
return
Syntax: return [status code]
Description: exit script and return status code
set_input
Syntax: set_input( file ), set_output( file ), set_error( file )
Description: input/output redirection
skip_line
Syntax: skip_line [(file)]
Description: discard the next line of input
subtype
Syntax: subtype newtype is oldtype
Description: create an alias for a type
system
Syntax: system( commandstring )
Description: run a BASH shell command
trace
Syntax: trace [true | false]
Description: show verbose debugging information
typeset
Syntax: typeset var [is type]
Description: change the type of a variable, declaring it if necessary.
Cannot be used in scripts or with pragma ada_95.
unset
Syntax: unset ident
Description: delete an identifier. Cannot be used in scripts or with
pragma ada_95.
wait
Syntax: wait
Description: wait for all background commands to finish.
while
Syntax: while condition loop ... end loop
Description: while loop - repeat the loop until the condition is false
?
Syntax: ? expression
Description: put_line to standard output. Cannot be used with pragma
ada_95.
ASCII.NUL - control-@
ASCII.SOH - control-A
ASCII.STX - control-B
ASCII.ETX - control-C
ASCII.EOT - control-D
ASCII.ENQ - control-E
ASCII.ACK - control-F
ASCII.BEL - control-G
ASCII.BS - control-H
ASCII.HT - control-I
ASCII.LF - control-J
ASCII.VT - control-K
ASCII.FF - control-L
ASCII.CR - control-M
ASCII.SO - control-N
ASCII.SI - control-O
ASCII.DLE - control-P
ASCII.DC1 - control-Q
ASCII.DC2 - control-R
ASCII.DC3 - control-S
ASCII.DC4 - control-T
ASCII.NAK - control-U
ASCII.SYN - control-V
ASCII.ETB - control-W
ASCII.CAN - control-X
ASCII.EM - control-Y
ASCII.SUB - control-Z
ASCII.ESC - Escape key
ASCII.FS
ASCII.GS
ASCII.RS
ASCII.US
ASCII.DEL - ASCII 127, delete key
ASCII.Exclam - "!"
ASCII.Quotation - """"
ASCII.Sharp - "#"
ASCII.Dollar - "$"
ASCII.Percent - "%"
ASCII.Ampersand - "&"
ASCII.Colon - ":"
ASCII.Semicolon - ";"
ASCII.Query - "?"
ASCII.At_Sign - "@"
ASCII.L_Bracket - "["
ASCII.Back_Slash - "\"
ASCII.R_Bracket - "]"
ASCII.Circumflex - "^"
ASCII.Underline - "_"
ASCII.Grave - "`"
ASCII.L_Brace - "{"
ASCII.Bar - "|"
ASCII.R_Brace - "}"
ASCII.Tilde - "~"
ASCII.UC_A - "A"
...
ASCII.UC_Z - "Z"
ASCII.LC_A - "a"
...
ASCII.LC_Z - "z"
End of Document