© Copyright 2000 Handwave Inc. All Rights Reserved.

HandScript Language Specification

1. Introduction

HandScript is a simple scripting language for handheld computers based on Javascript.  HandScript is designed to be usable in small pieces, so a single expression or statement is a valid program.  HandScript can explicitly represent user data, facilitating creation of databases.  HandScript is limited to a small number of built-in features, making it easy to master.  HandScript is extensible in HandScript and in C.

2. Comparison to Javascript and WMLScript

HandScript is derived from Javascript and WMLScript (WAP [Wireless Access Protocol] Markup Language Script).  Loosely speaking it is "between" those languages: a subset of Javascript and a superset of WMLScript.  However, in the ability to directly represent data it surpasses both Javascript and WMLScript.

A Subset of Javascript

HandScript is Javascript without objects.  It is a language of functions and libraries of functions. Its types are number, string and array.  Numbers include integers and floating point.  Arrays are generalized to allow floating point and string indexes.  Strings are indexable with integers.

A Superset of WMLScript

HandScript is WMLScript plus arrays and the ability to subscript strings.  HandScript includes WMLScript "invalid" type.  HandScript uses 64-bit floating point, whereas WMLScript specifies 32-bit floating point.  HandScript, like WMLScript, supports libraries of functions.

3. Types

HandScript values are one of four types: number, string, array and invalid.  Numbers use 64-bit floating-point representation.  Strings are sequences of 8-bit Ascii values.  Arrays are containers for values of any type.  The keyword invalid identifies a unique value whose type is not number, string or array.

HandScript is a "dynamically typed" language.  That means that variables do not have a fixed type associated with them, but instead are capable of containing values of any type.  The same variable can contain values of different types at different times.

4. Statements

HandScript contains most of the familiar statements of C, Javascript and Java.  (See section 12 for the precise syntax specification of all HandScript statements).  HandScript includes assignment, if, for, while, do, continue, break, return and var statements.

Example Statements:
    var a = 5, b = a+2;    //variables can be declared before use
    c = b*6.2;             //but they need not be declared

    if (a+1>b) a--;        //if statement
    else a++;              //with optional else

    for (i=0; i<10; i++){  //for statement, 3-part form
         a[i] = 0;
    }

    for (i in a) {        //for statement, 1-part form
        a[i] = 0;
    }
    
    while (i>=0) a[i] = b[i--];    //while statement

    do {                  //do statement
         a[i] *= 2;
         if (a[i]>limit)
              break;      //break statement
         i += 3;
    } while (i<#a);

5. Functions

Functions are used to extend the HandScript language.  The Javascript syntax for function declarations is used.  For example:
    function factorial(n){
         if (n<2) return 1;
         return n*factorial(n-1);
    }
This is a function with name factorial and formal parameter n.  It calls itself recursively to compute its result.

6. Libraries

Libraries contain groups of related functions.  The library that contains a function is identified in the function name.  A function name consists of either a single identifier, or two identifiers separated by a period.  For example factorial and math.sqrt.  When there are two identifiers in a name, the first identifier defines the library to which the function belongs.  A single identifier name may be thought to belong to the unnamed library.  For the two example function names, factorial belongs to the unnamed library and math.sqrt belongs to the math library.

Libraries are a form of name space control.  They help a programmer (or multiple programmers) avoid using the same name for two different purposes.  If a library name is unique, then the only potential function name collisions are within the library.  This is a much more manageable problem than assuring that a name is unique from all other names ever used.

7. Variables

HandScript variables are named containers for values.  A HandScript program dynamically assigns values to variables.  Values have a type, either number, string, array or invalid.  At different times a variable may have different types of values.  For example:
    a = 15;
    if (a>b) a = "bigger";
    else if (a<b) a = "smaller";
    else a = invalid;
Variables are either local to a function or global to all functions.  The value of a local variable is no longer available when the function defining the variable returns.  The value of a global variable may be shared among multiple functions or separate invocations of the same function.  Local variable names start with a lowercase letter, whereas global variable names start with an uppercase letter.  In the example below, the global variable Customer contains an array.  The function cust.define saves an association between id and name in the array:
    function cust.define(id, name){
         Customer[id] = name;
    }
Variable names can also specify a library.  Such names consist of two identifiers separated by a period, where the first identifier defines the library to which the variable belongs, and the case of the first character of the second identifier determines whether the variable is local or global.  As in function names, libraries provide name space control for variable names.  The example above can be implemented with a library variable cust.Name as follows:
    function cust.define(id, name){
         cust.Name[id] = name;
    }

8. Strings

Strings are sequences of 8-bit Ascii characters.  String literals are enclosed in either single or double quotes (e.g., "sam" or 'joe').  Strings operators support concatenation, comparison, slicing and subscripting.  Examples are:
    return "Mr. " + firstName + " " + lastName;  //concatenation

    if (name=="joe") joeCt++;  //equality comparison

    s1 = s[0..4];    //slice, a string of first 5 characters

    c = s[i];        //subscript, a string of a single character
Strings are immutable, their individual characters cannot be changed.  However, strings can be used to create new strings through subscripting, slicing and concatenation.

9. Arrays

Arrays are containers for associations between indices and values.  Indices are numbers or strings.  Values are numbers, strings or arrays.

Array Initializers

Array Initializers are array creation expressions.  Examples are:
    {}        //an empty (0 valid elements) array

    {"sam", "joe"}    //this is equivalent to the array below
    {0:"sam", 1:"joe"} //associate 0 with "sam", 1 with "joe"

    {i+j, i-j, 20:i*j, i/j)    //these two are equivalent
    {0:i+j, 1:i-j, 20:i*j, 2:i/j}

    {{i, j}, {i+1, j-1}}    //nested arrays

    {"first":"al", "last":"dugan", "tels": {"668-2000","776-0123"}}

Array Access

Array contents are accessed via subscripting.  In the example below, an empty array is assigned 10 elements.  The array automatically grows as needed to contain more elements.
    a = {};
    for (i=0; i<10; i++) a[i] = i*i; 
    // now, a == {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}
Array subscripts can be of type number or string.  For example:
    if (person["last"]=="dugan") telephones = person["tels"];
Array entries can be removed by assigning invalid.  For example:
    a = {"pete", "mary", "tom"};
    a[1] = invalid;    //a now contains {0:"pete", 2"tom"}
The for in statement iterates over the indices of an array, so it handles the results of deleted entries, as in the preceding example.

Array Databases

Array notation can be used to concisely create and access persistent databases.  The unary @ operator applied to a string opens a database with name defined by the string.  This database can then be referred to as a subscripted array to create and access its records.  For example, the code below creates the database named "Friends" containing 2 records.
    db = @"Friends";
    db["sam"] = {"name": "sam smith", "kids": {"bill", "sally"}};
    db["joe"] = {"name": "joe hill", "kids":{}};
After the database is created with this code, it can be queried as follows:
    f = @"Friends";
    f["sam"]["kids"]    //this returns {"bill", "sally"}
A copy of an array database can be made simply as follows:
    original = @oldname;  //get array accessor to old database
    copy = @newname;  //create new database and get array accessor
    for (i in original) copy[i] = original[i];  //copy record

10. Unique HandScript Operators

HandScript defines the following additional unary operators (not defined in JavaScript or WMLScript):
OperatorOperand Result
#Array or String The number of valid elements in an array or string
##String The ascii value of the first character of string operand
^String Display the string in a dialog box
@String Open an array database with the name of the string operand
&Any Return an integer pointer to a HandScript variable (for C calls)
%Number Allocate string with integer operand number of characters (for C calls)
|Number Set stack pointer to integer operand (for C calls)

11. C Calls

HandScript code can call C code using the Palm OS supported trap call mechanism.  This enables calling the operating system as well as calling C code that has been packaged as a dynamic library.  C interfaces are defined in terms of typed arguments.  HandScript defines a syntax for describing C interfaces.  The HandScript runtime for C trap call converts the HandScript argument values to the associated C types.

Calling C from HandScript should be done carefully.  A HandScript-only environment is crash free (theoretically at least), in that catastrophic user errors are detected and reported.  On the other hand, calling C code from HandScript and passing bad arguments will very likely cause a crash that requires a system reset.

Below is an example calling OS function DmGetNextDatabaseByTypeCreator that illustrates most of the principles in calling C from HandScript:
    err = [UInt16 0xA078, UInt8 newSearch, MemPtr state, 
          UInt32 type, UInt32, creator, UInt8 onlyLatest,
          UInt16Ptr &card, UInt32Ptr &dbID];
In this example, the return type is UInt16, the trap selector for DmGetNextDatabaseByTypeCreator is 0xA078, and the remaining elements are pairs of argument types and values.  Arguments are pushed C-style, right-to-left.  Each argument gets converted to the specified type before the call is done.

C Pointer Arguments

Passing pointer arguments from a language that doesn't have pointers requires some understanding of C.  There are two separate cases, both illustrated in the example above: (1) pointers to Strings and structs, and (2) pointers to numbers.  There are nine C types ending in "Ptr" (see next section for a complete list of types).  One type, MemPtr, is used for passing strings and structs.  The other 8 C pointer types are used for passing pointers to various kinds of integer and floating point numbers.

For MemPtr, valid HandScript argument types are string and integer.  For MemPtr with a HandScript integer argument, the integer value is passed.  Use an integer to pass a null (zero) pointer.  If an integer is non-zero, it must be a valid C address - most likely obtained by an earlier C call.  For MemPtr with a HandScript string argument, the address of the string is passed.

For the C pointer to number types, for example UInt16Ptr, pass the address of a HandScript variable that contains the number or will receive the number.  This is done using the "&" operator (see example above and &card argument value).  Note that a pointer can be used to pass a value in to a C call, receive a value out from a C call, or both.  HandScript cannot know which is the case, so it assumes both.  One implication of this is that if a pointer to a variable is passed, HandScript requires that the variable contains a number, even if the argument is output only.

Trap Selectors

The trap selector is the 16-bit argument to the hardware trap instruction that identifies which C routine to call.  HandScript supports a variant of the selector: when the selector value is greater than 0xFFFF, it is a selector pair.  In this case, the higher-order 16 bits is the trap selector, and the lower order 16 bits is the sub-selector, which is pushed on the stack before the call.  This form is used to call the Handspring API.

12. HandScript Syntax

Lexical Grammer

Tokens

token:
keyword
identifier
constant
string-literal
operator

Keywords

keyword: one of
breakcontinuedivdo
elsefalseforif
invalidreturntruetypeof
varwhile

Names

name:
identifier
identifier . identifier

identifier: one of
nondigit
identifier nondigit
identfier digit

nondigit: one of
_
a  b  c  d  e  f  g  h  i  j  k  l  m
n  o  p  q  r  s  t  u  v  w  x  y  z
A  B  C  D  E  F  G  H  I  J  K  L  M
N  O  P  Q  R  S  T  U  V  W  X  Y  Z

digit: one of
0  1  2  3  4  5  6  7  8  9

Constants

constant:
floating-constant
integer-constant
true
false
invalid

floating-constant:
fractional-constant exponent-part
digit-sequence exponent-part

fractional-constant:
digit-seqenceopt . digit-sequence
digit-sequence .

exponent-part:
e signopt digit-sequence
E signopt digit-sequence

sign: one of
+  -

integer-constant:
decimal-constant
octal-constant
hexadecimal-constant

decimal-constant:
nonzero-digit
decimal-constant digit

nonzero-digit: one of
1  2  3  4  5  6  7  8  9

octal-constant:
0
octal-constant octal-digit

octal-digit: one of
0  1  2  3  4  5  6  7 

hexadecimal-constant:
0x hexadecimal-digit
0X hexadecimal-digit
hexadecimal-constant hexadecimal-digit

hexadecimal-digit: one of
0  1  2  3  4  5  6  7  8  9
a  b  c  d  e  f 
A  B  C  D  E  F 

String Literals

string-literal:
"double-quote-sequenceopt"
'single-quote-sequenceopt'

double-quote-sequence:
double-quote-char
double-quote-sequence double-quote-char

single-quote-sequence:
single-quote-char
single-quote-sequence single-quote-char

double-quote-char:
escape sequence
any member of the source character set except the double-quote " backslash \ or new-line character

single-quote-char:
escape sequence
any member of the source character set except the single-quote ' backslash \ or new-line character

escape-sequence:
simple-escape-sequence
octal-escape-sequence
hexadecimal-escape-sequence

simple-escape-sequence: one of
\'  \"  \?  \\ 
\a  \b  \f  \n  \r  \t  \v

octal-escape-sequence:
\octal-digit
\octal-digit octal-digit
\octal-digit octal-digit octal-digit

hexadecimal-escape-sequence:
\x hexadecimal-digit
hexadecimal-escape-sequence hexadecimal-digit

unicode-escape-sequence:
\u hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit

Operators

operator: one of
[  ]  (  )  {  }
++  --  &  *  +  -  ~  !
/  %  <<  >>  <  >  <=  >=  ==  !=  ^  |  &&  ||
=  *=  /=  %=  +=  -=  <<=  >>=  &=  ^=  |=
,  #  ##  @  ?  :  -> 

Phrase Structure Grammar

Expressions

primary:
constant
string-literal
( expression )
variable-access
array-initializer
function-call
trap-call

variable-access:
name
primary [ expression ]
primary [ expression .. expression ]

array-initializer:
{ element-listopt }

element-list:
element
element-list , element

element:
expression
expression : expression

function-call:
name ( argumentsopt )
primary ( argumentsopt )

arguments:
expression
arguments , expression

trap-call:
[ type trap-selector trap-argumentsopt ]

type: one of
Int8Int16Int32 UInt8UInt16UInt32Float64
Int8PtrInt16PtrInt32Ptr UInt8PtrUInt16PtrUInt32PtrFloat64Ptr
MemPtrVoid

trap-selector:
expression

trap-arguments:
trap-argument
trap-arguments , trap-argument

trap-argument:
type expression

postfix-expression:
primary
variable-access ++
variable-access --
postfix-expression -> dereference-type

dereference-type: one of
Int8Int16Int32 UInt8UInt16UInt32Float64
MemPtr

unary-expression:
postfix-expression
++ variable-access
-- variable-access
unary-operator unary-expression
& name

unary-operator: one of
+  -  *  ~  !  #  ##  @  ^  typeof 

multiplicative-expression:
unary-expression
multiplicative-expression * unary-expression
multiplicative-expression / unary-expression
multiplicative-expression div unary-expression
multiplicative-expression % unary-expression

additive-expression:
multiplicative-expression
additive-expression + multiplicative-expression
additive-expression - multiplicative-expression

shift-expression:
additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression

relational-expression:
shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression

equality-expression:
relational-expression
equality-expression == relational-expression
equality-expression != relational-expression

and-expression:
equality-expression
and-expression & equality-expression

exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression

inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression

conditional-and-expression:
inclusive-or-expression
conditional-and-expression && inclusive-or-expression

conditional-or-expression:
conditional-and-expression
conditional-or-expression || conditional-and-expression

conditional-expression:
conditional-or-expression
conditional-or-expression ? expression : conditional-expression

assignment-expression:
conditional-expression
variable-access assignment-operator assignment-expression

assignment-operator: one of
=  *=  /=  div=  %=  +=  -=  <<=  >>=  &=  ^=  |= 

expression:
assignment-expression
expression , assignment-expression

Statements

statement:
expression-statement
selection-statement
iteration-statement
jump-statement
var-statement

block:
{ statement-listopt }
statement

statement-list:
statement
statement-list statement

expression-statement:
expressionopt ;

selection-statement:
if ( expression ) block
if ( expression ) block else block

selection-statement:
while ( expression ) block
do block while ( expression )
for ( expressionopt ; expressionopt ; expressionopt ) block
for ( name in expression ) block

jump-statement:
continue ;
break ;
return expressionopt ;

var-statement:
var variable-declaration-listopt ;

variable-declaration-list:
variable-declaration
variable-declaration-list , variable-declaration

variable-declaration:
name variable-initializeropt

variable-initializer:
= conditional-expression

Functions

function:
function name ( name-listopt ) block

name-list:
name
name-list , name
© Copyright 2000 Handwave Inc. All Rights Reserved.