-
Notifications
You must be signed in to change notification settings - Fork 3
Reference
BlueScript is a scripting language for programming a microcontroller. It borrows its syntax from TypeScript and hence it is regarded as a small subset of TypeScript. But BlueScript also adopts several unique semantic differences from TypeScript.
BlueScript is a subset of TypeScript because, for example, it (currently) does not support exceptions, promises, async/await, or certain built-in objects.
On the other hand, unlike TypeScript, BlueScript supports integer
and float
primitive types,
and a BlueScript program is executed relying on static type information.
When a variable is statically typed as integer
,
it always holds a native 32bit integer during runtime
as the C/C++ language does. It never holds another type of value, and thus no runtime type check is necessary.
Furthermore, BlueScript supports simple gradual typing.
BlueScript provides six primitive types as well as object types:
-
integer
(32bit integer) -
number
(an alias ofinteger
) -
float
(32bit floating-point number) string
boolean
-
null
andundefined
(they are the same) any
Any kind of value can be implicitly converted into any
type, and vice versa.
- When an
integer
value is converted, the resulting value is represented as a 30bit integer. - When a
float
value is converted, the resulting value is represented as a 30bit floating-point number, where only 6 bits are allocated for an exponent instead of 8 bits. - For logical operations and the condition expressions of coditional/loop statements
such as
if
andwhile
, 0, 0.0,false
,null
, andundefined
are considered as false while other values are true.
-
null
andundefined
(they are the same) true
false
- Numbers such as
7
and0.3
- Character strings such as
"text"
and'text'
- Arrays such as
[1, 2, 3]
Note that object literals such as { x: 3, y: 4 }
are not supported.
An object must be created by the new
operator as an instance of a class.
An object represents a character string.
BlueScript currently supports arrays of integer
, float
, boolean
, string
, class types,
array types, and any
-type.
Their names are T[]
, where T
is an element type.
Array types are invariant. For example, integer[]
is not a subtype of any[]
or its super type.
But array types can be implicitly converted into any
-type, and vice versa.
In other words, a reference to an array of integer
, any
, etc. is implicitly converted into an any
-type value.
An any
-type value is also implicitly converted into a reference to an array
if the any
-type value points to an array object of that array type.
Otherwise, a runtime error is thrown.
Array literals are defined using square brackets, with elements separated by commas.
let arr = [1, "Foo", 42];
The type of an array literal is array of the most specifict super
type of the static types of all the elements.
If there exists such a super type, the type of the array literal is
array of any
.
An array object is created by new Array<T>(size, value)
. Here, T
is a meta variable representing a type name.
size
is the number of the array elements. value
is the initial value for the array elements.
T
can be integer
, float
, boolean
, string
, an array type, a class type, or any
-type.
let iarr = new Array<integer>(3, 0);
When the element type is integer
, float
, boolean
, or any
,
the second argument to the Array
constructor can be omitted.
The initial values are zero, false
, or undefined
.
For example, new Array<integer>(7)
is a valid expression, and it
constructs an array including 7 elements.
Array types are represented by Type[]
. Here, Type
is a meta variable representing the type name of array elements.
let iarr: integer[] = [1, 2, 3];
let sarr: string[] = ['one', 'two', 'three'];
Note that Array
or Array<integer>
is not a valid type name.
Only numeric indices are supported for accessing array elements.
let arr = [1, 3, 4];
print(arr[0]); // 1
Accessing an index out of bounds will result in a runtime error.
let arr = [1, 2, 3];
print(arr[5]); // ** error: array index out of range: 5
Currently, array methods such as push
, pop
, map
, filter
, etc., are not supported in BlueScript.
The length
property represents the length of an array.
let arr = [1, 2, 3];
print(arr.length); // 3
If the type of arr
is any
-type, the type of arr[i]
is any
.
arr[i] = v
throws a runtime error
if v
is not a value of the element type for the array
that arr
points to.
For example,
let arr: integer[] = [1, 2, 3];
let arr2: any = arr;
print(arr2.length) // 3
print(arr2[0]) // 1
print(typeof arr2[0]); // 'any'
arr2[1] = 'five'; // runtime error
An Uint8Array
object is also available. Its elements are unsigned 8 bit integers.
let arr = new Uint8Array(3, 0) // create an array containing 3 elements. Their initial values are 0.
print(arr[1]) // 0
arr[0] = 7
print(arr[0]) // 7
print(arr.length) // 3
Then second argumemnt to the constructor of `Uint8Array' cannot be omitted.
The operands' types of the increment and decrement operators must be integer
, float
, or any
.
-
Postfix Increment/Decrement Operators
The value is incremented or decremented by 1, and the original value is returned.let x = 1; print(x++); // 1 print(x); // 2 let y = 1.0; print(y--); // 1.0 print(y); // 0.0
-
Prefix Increment/Decrement Operators
The value is incremented or decremented by 1, and the updated value is returned.let x = 1; print(++x); // 2 print(x); // 2
BlueScript supports the following unary operators:
-
+
(Unary plus, returns the value of its operand. The operand's type must beinteger
,float
, orany
.) -
-
(Unary negation, returns the negation of its operand. The operand's type must beinteger
,float
, orany
.) -
~
(Bitwise NOT. The operand's type must beinteger
orany
.) -
!
(Logical NOT. The operand's type can be any kind of type.)
print(-3) // -3
The operands' types must be integer
, float
, or any
.
If either the left operand or the right operand is any
, the resulting type is any
.
If either left or right is float
, the resulting type is float
. Otherwise, it is integer
.
-
+
(Addition) -
-
(Subtraction) -
*
(Multiplication) -
/
(Division) -
%
(Modulus) The operands must be aninteger
value or anany
-type value holding aninteger
value. -
**
(Exponentiation) The operands are converted intodouble
values, andpow()
in C computes the result.
The operands' types must be integer
, float
, string
, or any
. The resulting type is boolean
. Both operands share the same type or any
-type.
If a left or right operand is any
-type, the value of the other operand is converted into an any
-type value before comparison.
-
<
(Less than) -
>
(Greater than) -
<=
(Less than or equal to) -
>=
(Greater than or equal to)
-
==
and===
are used as equality operators. Their semantics is the same as the===
operator in JavaScript. -
!=
and!==
are used as inequality operators. Their semantics is the same as the!==
operator in JavaScript.
If either the left operand or the right operand is a boolean
type,
the other operand must be also boolean
type.
The operands' types must be integer
. The type of the resulting value is integer
.
-
<<
(Left shift) -
>>
(Right shift) -
>>>
(Unsigned right shift)
The operands' types must be integer
. The type of the resulting value is integer
.
-
&
(AND) -
|
(OR) -
^
(XOR)
-
&&
(Logical AND) -
||
(Logical OR)
-
typeof
(returns the static type name of its operand. Unlike JavaScript, it is not a dynamic type name.) -
instanceof
(checks whether the left operand is an instance of the class given as the right operand or its subclass. The right operand may bestring
orArray
. The type of the left operand must be a class type,string
, an array type, orany
.)
obj instanceof Array
results in true
when obj
is an array object no matter what its element type is.
The ternary operator ? :
is used for conditional expressions:
let result = condition ? trueValue : falseValue;
BlueScript supports the following assignment operators:
=
-
+=
,-=
,*=
,/=
(Compound assignment operators. The operands' type must beinteger
,float
, orany
.) -
%=
(The operands' type must beinteger
orany
.)
Variables in BlueScript are declared using let
or const
.
let x = 10;
let y: float = 5.5;
const t: boolean = true
Type annotations are optional. When they are ommitted, the variables' types are determined by type inference.
-
while loop
let i = 0; while (i < 10) { print(i); i++; }
-
do-while loop
let i = 0;
do {
print(i);
i++;
} while (i < 10);
-
for loop
for (let i = 0; i < 10; i++) { print(i); }
-
break and continue
for (let i = 0; i < 10; i++) { if (i == 5) { continue; } if (i == 8) { break; } print(i); }
-
if … else …
let a = 10; if (a > 5) { print("Greater than 5"); } else { print("Less than or equal to 5"); }
Functions are declared with the function
keyword.
Function declarations must be at the top level.
They must not be declared inside a function body or an expression.
function add(a: integer, b: integer): integer {
return a + b;
}
A function parameter without a type annotation is typed as any
.
A return type is optional.
When it is omitted, it is determined by type inference.
If type inference fails, the return type is either any
or void
.
A function can be redefined, but a new definition must share the same parameter types and return type.
An arrow function is also available. It can be created not only at the top level but also within a function body.
let add = (a: integer, b: integer): integer => a + b;
An arrow function creates a closure.
An object is created as an instance of class.
The type of the object is its class name.
An object can be implicitly converted into any
type, and vice versa.
A class must be defined by a class declaration.
A class expression is not supported.
Classes are declared by using class
keyword.
class Rectangle {
height: float;
width: float;
constructor(height: float, width: float) {
this.height = height;
this.width = width;
}
getArea() {
return this.height * this.width;
}
}
A property may have a type annotation, but a type annotation is optional.
In the code above, the types of properties height
and width
are float
.
All class declarations, properties, and methods are public
.
No access modifiers such as private
and readonly
are (currently) not supported.
A class can inherit from another class.
extends
keyword is used to specify a super class.
class Square extends Rectangle {
constructor(sideLength: float) {
super(sideLenght, sideLength);
}
}
A constructor must first invokes the constructor of its super class. A subclass is a subtype of the type representing its super class.
new
keyword is used to create a class instance.
let rect = new Rectangle(13, 15);
Properties and methods are accessed using the dot notation.
print(rect.height); // 13
print(rect.getArea()); // 195
Unlike TypeScript, a method is not a property holding a function object.
It may not be accessed as a property.
For example, since getArea
is a method, the following code is not valid in BlueScript.
let m = rect.getArea; // error
The rect
objecrt does not have a property named getArea
.
When a property's type is integer
or float
,
an object may hold only a 30bit value as the property's value.
If a class has a property of object type,
an integer
or float
property of its subclass holds a 30bit value.
Otherwise, it holds a 32bit value.
A property must be explicitly initailized in a constructor. A property declaration (currently) must not have an initializer, which is an expression computing the initial value of that property.
class Rectangle {
height: float = 10.0; // error
width: float = 10.0; // error
}
This is valid in TypeScript, but it is not in BlueScript.
= 10.0
must be erased.
In a constructor, a property is initialized through this
.
this
is a special variable that is available only in method bodies
and a constructor.
It refers to their object.
Unlike TypeScript, this
is not available in a function body or at the top level.
A class type is not a super type or a subtype of null
type.
So, a variable of a class type may not be set to null
.
Only a variable of a nullable type may be set to null
.
A nullable type is constructed from a class type.
Suppose that T
is a class type name.
Then, T | null
and T | undefined
are nullable types
(Note that null
and undefiend
are identical in BlueScript).
A variable of T | null
may be set to either a T
object or null
(or undefined
).
let r: Rectangle | null = null
r = new Rectangle(3.0, 4.0)
A nullable type is also constructed from the string
type and array types.
All the following types are valid nullable types.
string | null
integer[] | null
string[] | null
Uint8Array | null
However, integer | null
or float | null
is not a valid type.
If type T
is a subtype of S
, then T | null
is also a subtype of S | null
.
BlueScript (currently) supports only a very simple type guard.
If a local varialbe of type T | null
is tested for null in the condition expression of a if
statement, that variable is treated as a variable of type T
in the then clause or the else clause.
function area(r: Rectangle | null): float {
if (r == null)
return 0.0;
else {
// the static type of r is Rectangle. Not Rectangle | null.
return r.getArea();
}
}