Language Overview
VioletScript is a robust strongly-typed scripting language. Its syntax is similiar to JavaScript, but it has different semantics.
VioletScript is designed to have a performance similiar to Java and C#, with a very pleasing syntax familiar for JavaScript developers.
Quick Tour
Why
VioletScript is a faster version of JavaScript efficient as C# or Java.
Status
- Type checker is done.
- Codegen is not yet done. It'll target either WebAssembly or C++.
Basics
trace('Hi!')
var x: Number = 0
var y = 0 // y: Number
const z = 0
var w: * = undefined // '*' is the any type
function f1(): Number {
return Infinity
}
function f2(): Number (
Infinity
);
// you can shadow variables
function shadowing(): void {
'use shadowing'
const x = false
const x = ''
}
function typeSystem(): void {
const array: [Number] = []
const tuple: [String, Boolean] = ['', false]
const union: Number | undefined | null = null
const nullable: null | Boolean
const nullable: Boolean? // equivalent to previous constant
// records are immutable structures
const record: {x: Number, y: Number} = {x: 10, y: 10}
// the following have equivalent types
const record: {x?: Number} = {};
const record: {x: undefined | Number} = {};
// as you saw above, a record field is optional
// when it can contain undefined.
// function types
const fn: (...arguments: [Number]) => void = () => {}
}
type D = Decimal;
function nullability(): void {
// asserts that `o` is non-null and non-undefined;
// returns a type without undefined and null.
o!
// optional chaining
o?.x.y?.z?.[i]?.()
a?.[i]
f.()
}
Enums
An enum is an object...
- represented in memory as a primitive number;
- whose possible variants are associated with...
- an unique user friendly string and
- an unique number;
- that can define custom properties;
- that, where expected, a variant can omit its name through a string literal;
enum E {
X;
Y = 'y';
Z = ['z', 10];
function f(): void {
trace(this.valueOf());
}
}
const e: E = 'x';
e.f(); // 0
e.valueOf() // 0
e.toString() // 'x'
const e: E = 0 // ERROR! number must be
// explicitly converted
const e: E = 'inexistent'; // ERROR! doesn't exist
Note that the default user friendly string is a conversion from SCREAMING_SNAKE_CASE
(constant name) to screamingSnakeCase
.
Flags
Flags enums have many methods by default, such as toggle()
and filter()
.
[Flags]
enum F { X; Y; Z; }
const f: F = ['x'];
const f: F = {x: true};
const f: F = f.toggle('x');
trace('x' in f);
trace('x' not in f);
Classes
// generic class
class C.<T> {
var x: T
// constructor
function C(x: T) {
this.x = x
}
// the type `T!` can be used to remove
// any undefined and null from the parameter type.
}
Packages and Namespaces
// shares items to all scripts.
package q.f {
const someString = 'violetscript'
}
import q.f.*;
import q.f.someString;
// block brackets are optional
package q.b;
// a namespace acts as a simple container for
// other items, similiar to a singleton.
namespace Q {
class C {
}
// define a function using the reserved word 'for'.
// use '#' to escape a reserved word.
function #for(x: Number): Number (
x + 10
);
}
Q.for(10);
Visibility
Everything is public
by default, so you don't need to use visibility modifiers:
public
private
protected
internal
They're also verbose, so you may prefer using a _
prefix.
Type Testing
function typeTesting(): void {
if (animal is falcon: Falcon && falcon.name.startsWith('F')) {
// falcon: Falcon
}
switch type (object) {
case (long: Long) {
// Long
}
default {
// anything else
}
}
}
Destructuring
const {} = o
const [a] = o
// use '!' to assert non-null
// and non-undefined
const [a!] = a
const {x!: {}} = o
({} = o); // destructuring assignment
Include
Use include
to:
- Fragment a class into multiple files.
- Specifying the initialization order of static properties by including scripts in the wished order.
include './anotherScript';
Properties
o.x
and o['x']
are not the same thing as in ECMAScript. o.x
and Reflect.get(o, 'x')
are equivalent.
Equality
Auto-boxed types do not lose equality.
var x: Object = 0;
var y: Object = 0;
assert(x == y);
Decorators
[D]
class C {
}
Note that six lexical decorator names are reserved in different contexts.
Flags
is reserved forenum
Value
is reserved forclass
DontInit
is reserved forclas
Metadata
is always reservedAllow
is always reservedWarn
is always reservedFFI
is always reserved
You can still use these decorator names if they're in a namespace or package:
[q.b.Metadata]
class C {
}
Markup
A class must implement IMarkupContainer
for supporting children in markup.
// equivalent
var o = new C
o.x = Infinity
var o = <C x={Infinity}/>
Markup syntax is not based on XML and cannot contain text directly. There are different ways of adding text:
<Container><Text text='Some text'/></Container>
// if child type can be string
<Container>{['Some text', 'Another text']}</Container>
Primitive Types
Boolean
String
Number
Decimal
Byte
Short
Int
Long
BigInt
Code Safety
- Assignments are only allowed in proper contexts, otherwise that would lead to productivity issues.
- You will use the
!
operator very often, including in destructuring, for asserting that a base is notundefined
andnull
.
Reflection
Constructing Types Dynamically
Use Reflect.construct()
to construct a type dynamically, rather than new
:
const c = SomeClass;
const o = Reflect.construct(c, [firstArgument]);
Type Inspection
Use Reflect.describeType()
to get a type meta-object. It returns one of:
null
AnyType
UndefinedType
NullType
ArrayType
ClassType
EnumType
InterfaceType
TypeWithArguments
UnionType
TupleType
RecordType
FunctionType
TypeParameter
Frameworks
Unreal Engine
No plans yet.
import com.ue.*;
Language User Guide
This section lists all language features of VioletScript, avoiding grammar and implementation details.
Types
Nullability
The following line aliases the dynamic type (*):
type UndefinedOrNullOrObject = *;
The following line aliases the Object type:
type ObjectNotUndefinedNorNull = Object;
The following line escapes o from either null or undefined:
o!
The following line escapes T from union with null and undefined:
type NonNullT = T!;
Unifying type with null
The following line:
type NullableT = T?;
is equivalent to:
type NullableT = null | T;
It can also be wrote with a ?
prefix:
type NullableT = ?T;
Unifying type with undefined
type UndefinedOrT = undefined | T;
Proxies
VioletScript supports proxies to alter the behavior of certain operations. Currently, only class
and enum
can define proxies; interface
cannot define proxies.
Proxies cannot be overriden by subclasses.
Conversion Proxies
These proxies do not enable use of the literal this
.
class C {
proxy function convertImplicit(a: T): C? {
// implicit conversion from A to C
}
proxy function convertExplicit(a: T): C? {
// explicit conversion from A to C
}
}
Unary Operator Proxies
These proxies do not enable use of the literal this
.
class C {
// +o;
proxy function positive(a: C): R ...;
// -o;
proxy function negate(a: C): R ...;
// ~o;
proxy function bitNot(a: C): R ...;
}
Binary Operator Proxies
These proxies do not enable use of the literal this
.
class C {
// a === b;
proxy function equals(a: C, b: C): Boolean ...;
// a !== b;
proxy function notEquals(a: C, b: C): Boolean ...;
// a < b;
proxy function lt(a: C, b: C): Boolean ...;
// a > b;
proxy function gt(a: C, b: C): Boolean ...;
// a <= b;
proxy function le(a: C, b: C): Boolean ...;
// a >= b;
proxy function ge(a: C, b: C): Boolean ...;
// a + b;
proxy function add(a: C, b: B): R ...;
// a - b;
proxy function subtract(a: C, b: B): R ...;
// a * b;
proxy function multiply(a: C, b: B): R ...;
// a / b;
proxy function divide(a: C, b: B): R ...;
// a % b;
proxy function remainder(a: C, b: B): R ...;
// a ** b;
proxy function pow(a: C, b: B): R ...;
// a & b;
proxy function bitAnd(a: C, b: B): R ...;
// a ^ b;
proxy function bitXor(a: C, b: B): R ...;
// a | b;
proxy function bitOr(a: C, b: B): R ...;
// a << b;
proxy function leftShift(a: C, b: B): R ...;
// a >> b;
proxy function rightShift(a: C, b: B): R ...;
// a >>> b;
proxy function unsignedRightShift(a: C, b: B): R ...;
}
Index Proxies
These proxies enable use of the literal this
.
class C {
// o[i];
proxy function getIndex(i: I): V (
...
);
// o[i] = v;
proxy function setIndex(i: I, v: V): void {
...
}
// delete o[i];
proxy function deleteIndex(i: I): Boolean {
...
}
// v in o;
proxy function has(v: V): Boolean (
...
);
}
Iteration Proxies
These proxies enable use of the literal this
.
class C {
// for..in
proxy function iterateKeys(): Iterator.<K> {
// yield
}
// for each
proxy function iterateValues(): Iterator.<V> {
// yield
}
}
Type Conversions
Conversion Syntax
// optional conversion
v as T
v as? T
// forced conversion
v as! T
Enum(v)
// conversion constructors
String(v)
Number(n)
Any Type
The dynamic type (*) includes values of all types.
Undefined Type
The undefined type includes the value undefined.
Null Type
The null type includes the null value.
Boolean Type
The Boolean type includes the values false and true.
Number Type
There are different numeric types:
type DoublePrecisionFloatingPoint = Number;
type QuadruplePrecisionFloatingPoint = Decimal;
type Unsigned8BitInteger = Byte;
type Signed16BitInteger = Short;
type Signed32BitInteger = Int;
type Signed64BitInteger = Long;
type ArbitraryPrecisionInteger = BigInt;
String Type
The String type is UTF-16 encoded for compatibility with the ECMA-262 String type.
Code Points
You can easily iterate code points over a string with CodePointIterator
:
var iterator = 'v'.codePoints();
iterator.next(); // 0x76
iterator.next(); // 0 (no character)
iterator.hasRemaining; // false
Enumeration Types
Enumeration types define variants with an unique number and an unique string.
The following example program defines an enumeration with four variants:
enum E {
VARIANT_A;
VARIANT_B = 'customizedName';
VARIANT_C = 64;
VARIANT_D = ['anotherCustomizedName', 10];
}
// inference: 'variantA' converts to E.VARIANT_A
var e: E = 'variantA';
E.VARIANT_A.valueOf() == 0;
E.VARIANT_A.toString() == 'variantA';
E.VARIANT_B.valueOf() == 1;
E.VARIANT_B.toString() == 'customizedName';
E.VARIANT_C.valueOf() == 64;
E.VARIANT_C.toString() == 'variantC';
E.VARIANT_D.valueOf() == 10;
E.VARIANT_D.toString() == 'anotherCustomizedName';
Custom Properties
The block of an enum
definition can contain anything, as the following program demonstrates:
enum E {
function f(): void {
}
}
Type Inference
Wherever a value of an enum
is expected, a string literal can be used. In addition, for flags enumerations, an object initializer, array initializer or undefined
can also be used.
var e: E = E.VARIANT_A
var e: E = 'variantA'
// flags inference
var f: F = undefined
var f: F = {}
var f: F = []
Flags
Flags enumerations, prefixed with the special Flags
decorator, define combinatory variants. A variant number is either 1 or power of two.
[Flags]
enum F {
A; // 1
B; // 2
C; // 4
}
var f: F = [ 'a' ];
var q: F = { b: true };
f += 'c'; // f.include('c')
f -= 'c'; // f.exclude('c')
f = f.toggle('c');
f = f.filter('c');
'c' in f;
// returns F value with all flags present
F.all;
// checks if flags are empty
f == []
f == undefined
Custom Numeric Type
Any numeric type can be used, including floating points. By default enum
uses Int
.
Use the context word wraps
to use a custom numeric type for an enumeration.
enum E wraps BigInt {
}
Classes
class C {
// constructor
function C() {
super();
}
// override instance method
override function toString(): String (
'violetscript'
);
// final instance method: cannot be overriden
// by subtypes.
final function finalMethod(): void {
}
}
class F extends C implements I {
}
// generic class
class G.<T> {
}
// final class: cannot extend
final class Final {
}
Prohibit Object Initialiser
Use the DontInit
decorator to prohibit object initializer on a specific class.
[DontInit]
class C {
}
var o: C = {}; // VerifyError!
Method Overriding
- An override can specify either additional optional parameters or one additional rest parameter.
- An override can specify a more specific return type: either a subtype or, if the original method's return is
*
, any different type.
Interfaces
interface I {
// required method
function rf(): void;
// optional method
function of(): void {
}
}
// generic interface
interface G.<T> {
}
User Value Types
Value classes are passed by value. They can be defined by using the special Value
decorator, as follows:
[Value]
class V {
const x: Number;
const y: Number;
}
Fields are all read-only. You can re-assign a field from an existing instance like this:
o = { x: newValue, ...o };
Array Types
The Array type is dynamically-sized.
The following line:
type ListOfNumbers = [Number];
is equivalent to:
type ListOfNumbers = Array.<Number>;
Tuple Types
Tuple types are passed by value. They are written as two or more type expressions enclosed by square brackets. For example:
type T = [Number, String];
Record Types
Record types are immutable structures passed by value. They are written in curly brackets. For example:
type R = {x: Number, y: undefined | RegExp};
A field is optional when it possibly contains undefined
. The following types are equivalent:
type R1 = {x?: Number};
type R2 = {x: undefined | Number};
Field Order
The sequence of the record type fields is sensitive. A type {x: X, y: Y}
differs from {y: Y, x: X}
. This allows for organizing memory layout.
Function Types
Function types inherit the Function
class.
// parameterless
type F1 = () => void;
// with required parameter
type F2 = (a: Number) => void;
// with optional parameter
type F3 = (a?: Number) => void;
// with rest parameter
type F4 = (...a: [Number]) => void;
Parameter Names
A type (a: T) => void
differs from a type (_: T) => void
because the parameter names differ.
Union Types
type U = undefined | Number | Boolean;
// "|" prefix
type XoY =
| X
| Y
Member Order
The sequence of the union members is sensitive. A type X | Y
differs from Y | Z
. This allows for organizing memory layout.
Type Parameters
Type parameters can specify constraints.
class G.<T: I> // T implements or extends I
where T is K // T also implements or extends K
{
}
Type Aliasing
Use the context keyword type
for defining type aliases.
type AliasName = q.f.C;
type G.<T> = g.C.<T>;
Static Properties
Use the static
modifier to define a property that is attached to the type rather than attached to its instance.
class C {
static const x: Number = 10;
}
Expressions
Embed Expression
The context keyword embed
can be used to include text or octet-stream of relative path to the current script.
var ba:ByteArray = embed './octetStream.bin';
var str:String = embed './someText.txt';
Await Expression
The await
expression causes the surrounding function to be asynchronous, returning a Promise. It's currently not allowed in the top-level of a program.
Yield Expression
The yield
expression causes the surrounding function to be a generator, returning Generator
.
Default Expression
The default
expression returns the default value of the given type.
default(Number); // 0
Function Expression
a => 10;
() => 10;
(function(): void {})();
(function(): Number (10 ** 2))();
Markup Expression
VioletScript supports markup similiar to XML, with the only exception of text nodes.
Remarks:
- The markup syntax can be used to initialize any user class with the following restrictions:
- The class must not have a
DontInit
decorator. - The class constructor must be either empty or receive only optional parameters and/or rest parameter.
- The class must not have a
- A container class must implement
IMarkupContainer.<T>
. - A curly brackets into the markup must contain an expression of the array type.
const c = (
<Container>
<Item n=Infinity v={10**2} checked/>
{childrenArrayRest}
</Container>
);
// qualified tag name
<com.q.a.X/>;
// qualified tag name using colon
<s:Button/>;
const a: [Container] = <>
<Container/>
<!-- spread -->
{ [<Container/>,<Container/>,<Container/>] }
</>;
Object Initializer
Object initializer, written in curly brackets, supports shorthand property notation, trailling comma, spread components (...spreadObject
) and a suffix type annotation.
Object initializer can only initialize:
*
(instantiates an emptyObject
, not allowing spread)Map
- Flags enumeration
- Record type
- Class without a
DontInit
decorator
Additional semantics:
- Using object initializer to initialize a plain object results in an object whose
constructor
property returnsObject
. - Spread elements are evaluated before fields when initializing flags, record or class, that is, anything other than
Map
.
Array Initializer
Array initializer, written in square brackets, supports ellisions, spread components (...otherArray
) and suffix type annotation.
Array initializer can only initialize:
*
(instantiates a[*]
array)Array
Set
- Flags enumerations
- Tuples
Spread
A spread component can either be a compatible Array
, iterator or flags.
- Flags: Flags type itself.
- Any: Any at compile-time; at runtime it must be a compatible iterator or array, otherwise an error occurs.
- Set: Iterator.
- Array: Same array type or iterator.
- Map: Unallowed.
Member Expression
o.x;
// optional member access in case o is undefined or null
o?.x;
If o
is a package, then o.x
can resolve to a subpackage in last attempt.
Index Expression
Unlike EcmaScript, the index expression, in the form o[k]
, uses an indexing mechanism that is separate from the object properties mechanism. This resolves conflict of properties and indexes. Methods such as Reflect.get(...)
can be used in case a property must be dynamically resolved.
The index expression is indentation-aware.
o[k];
// optional index in case o is undefined or null
o?.[k];
Call Expression
Call expression is indentation-aware.
f();
// optional call in case f is undefined or null
f?.();
Special Behavior
- If
f
is an enumeration, the call expression corresponds to a forced conversion from either String or numeric value to the enumeration. - If
f
is a type, but not an enumeration, it corresponds to the use of thenew
operator.- If
f
is the String type, it corresponds to a string conversion.
- If
E(v)
T(ctorArguments)
String(v) // string conversion
Literal
Regular Expression Literal
/zxc/i
This Literal
this
String Literal
'violetscript'
Null Literal
null
Boolean Literal
false
true
Numeric Literal
0
Conditional Expression
c ? x : y;
Unary Expression
await f()
yield v
delete r[k]
typeof v
void v
!v
+v
-v
~v
v!
++v
--v
v++
v--
new C
Increment/Decrement Semantics
The increment and decrement operators can also be applied to expressions in the form x!
, such as o[k]!++;
.
Binary Expression
k in o;
k not in o;
x + y
x - y
x * y
x / y
x % y // remainder
x ** y
x && y
x ^^ y
x || y
x ?? y
x & y
x ^ y
x | y
x << y
x >> y
x >>> y
x == y
x != y
x === y
x !== y
x < y
x > y
x <= y
x >= y
nonDestructuringPattern = y
destructuringPattern = y
nonDestructuringPattern compound= y
v is T;
v is q : Q;
v instanceof T;
// optional conversion; both equivalent
v as T;
v as? T;
// forced conversion
v as! T;
Assignment
- Assignment is only allowed as a statement, as a
for
update and as the right-hand side of another assignment. - It is allowed to use compound assigning applied to non-null index:
o[k]! += 1;
Parentheses Expression
(v)
List Expression
x, y
Generic Instantiation Expression
tOrFunction.<...>;
Super Expression
super.xOrF
Statements
Expression Statement
expression;
Empty Statement
;
Super Statement
super();
Import Directive
import q.u.*;
import q.**; // recursive; imports `q` and all subpackages
import q.u.B;
import A = q.u.B;
import Qu = q.u.*;
Import from global
The global
identifier may be used to alias a property of the global package.
import GRegExp = global.RegExp;
Subpackage aliasing
A subpackage from a package can be accessed even when the base package is aliased.
// com.scientific.fns.f
import sci = com.scientific.*;
sci.fns.f();
If Statement
if (c)
{
//
}
else
{
//
}
Do Statement
do
{
//
}
while (c);
While Statement
while (c)
{
//
}
For Statement
for (i; c; u)
{
// procedure
}
for (var i; c; u)
{
// procedure
}
for (var i in o)
{
// procedure
}
for (i in o)
{
// procedure
}
for each (var i in o)
{
// procedure
}
for each (i in o)
{
// procedure
}
for..in
should work with:
- Object with
proxy::iterateKeys
for each
should work with:
- Object with
proxy::iterateValues
Iterable
Iterator
- Any type (
*
)
Break Statement
break;
break someLabel;
Continue Statement
continue;
continue someLabel;
Return Statement
return;
return v;
Throw Statement
throw someError;
Labeled Statement
someLabel: for (;;)
{
}
Switch Statement
Unlike EcmaScript, the switch statement does not fallthrough in cases, which prevents general programmer bugs.
switch (d)
{
case 10:
{
// procedure
}
default:
{
// procedure
}
}
Switch Type Statement
switch type (d)
{
case (n:Number)
{
}
default
{
}
}
Include Directive
Combines statement sequence from a script with the current statement sequence.
include './anotherScript';
This also allows for partially implementing classes, similiar to C#'s partial
classes. For example:
class C {
var x: Number = 10;
include './foo';
}
foo.vs:
function f(): void {
trace(this.x);
}
Path resolution
- You do not need to specify the
.vs
extension. - You do not need to specify
index.vs
when resolving to a directory.
// if './core' is a directory, the following lines
// are equivalent:
include './core';
include './core/index.vs';
Packages
It is allowed to define packages in an included script as long as it is included from a top-level context:
// foo.vs
include './bar';
// bar.vs
package q.b;
Visibility
include
inherits the scope from where it is included.
// foo.vs
include './bar';
class C {
}
// bar.vs
var x: C?;
With Statement
with (o)
{
// procedure
}
Use Namespace Directive
Opens namespace lexically.
use namespace someNS;
Use Resource Statement
Binds variables to block and automatically dispose resources through the use of the IDisposable
interface.
use resource (disposable = obj)
{
// procedure
}
Documentation Comments
VioletScript supports Markdown comments with special @
tags. They're called VioletDoc comments.
Here is an example:
/**
* The function `f` does nothing.
*
* @example
*
* ```
* f();
* ```
*
* @throws {ArgumentError} If argument is invalid.
*/
function f(): void {
}
Supported Tags
@deprecated
@hidden
@example Example section.
@param paramName Description.
@return A return value.
@throws {C} Optional description.
@internal Internal comment.
@field {x} Field commment
- Used internally when you add comment to a record field in a type alias to a record type.
- It allows dot too for documenting subfields.
Shortcut Reference Links
/**
* [lexicalItemName]
* [`lexicalItemName`]
* [customLexicalItemName][lexicalItemName]
*/
Lexical Structure
Escape Reserved Words
var #catch: Number = 10;
Indentation-Aware String Literal
var s = '''
Line 1
Line 2
''';
Hexadecimal and Binary Integer Literal
0x0A;
0b00010;
Packages
A package is a globally reusable namespace. The following program demonstrates basic use of package
definitions:
package {
// global package
public const globalX: Number = 10;
}
package com.qux.bar {
public function f(): void {
}
public function q(): void {
}
}
globalX;
global.globalX; // equivalent
com.qux.bar.f();
com.qux.bar.q();
global.com.qux.bar.f();
// open com.qux.bar in lexical scope
{
import com.qux.bar.*;
f();
}
When curly brackets are omitted, all the following statements are part of the package:
package com.fun;
public function haveFun(): String (
'haveFun'
);
Namespaces
namespace Q {
function f(): void {
}
}
Namespace Alias
namespace A = q.Q;
Variable Properties
// writable
var x: Number = 10
// read-only
const x: Number = 10
// type inference
const x = 10
Virtual Properties
function get x(): Number (
10 ** 2
);
function set x(v) {
}
Functions
function f(): void {
}
function fWithRequiredParameter(a: Number): void {
}
function fWithOptionalParameter(a: Number = 10): void {
}
function fWithRestParameter(...a: [Number]): void {
}
function fWithExpressionBody(): String (
'violetscript'
);
// native function
native function fNative(): void;
Generators
A function is a generator if it uses the yield
operator.
Remarks:
- Generator functions return a Generator object, which is an iterator.
- A generator function finishes returning
undefined
.
function f(): Iterator.<Number> {
yield 10;
}
const iterator = f(); // Iterator.<Number>
iterator .next(); // {done: false, value: 10}
iterator .next(); // {done: true, value: undefined}
Asynchronous Functions
A function is asynchronous if it uses the await
operator.
Remarks:
- Asynchronous functions return Promise.
- Any thrown errors will reject the Promise.
function f(): Number {
await a();
return 10;
}
Generic Functions
function genericFunction.<T>(): void {
}
Destructuring
Array Destructuring
Array destructuring syntax can in addition be used for tuples and user proxies.
[x, y] = someArray;
Record Destructuring
({x} = someObject);
Non-null assertion
You may get a verify error when destructuring from something that contains undefined
or null
. You can use exclamation (!
) to assert the base is non-null and non-undefined:
const [{x!: {y}}!]! = o;
Decorators
A decorator is a function that either returns void
or returns another function that returns void
, applied to either a type, property or method as expressions enclosed by square brackets. Decorators cannot be applied everywhere.
[D(x = 10)]
is equivalent to [D({x: 10})]
.
Note that 4 lexical names may be reserved in some contexts. Jump to the Reserved Lexical Decorators section below for quick information.
Decorators Applied to Types
function MyTypeDecorator(type: Class): void {
}
[MyTypeDecorator]
class C {
}
Decorators Applied to Properties
function MyFieldDecorator(o: C, {name}: Binding): void {
trace(name);
}
class C {
[MyFieldDecorator]
public var x: Number;
}
Decorators Applied to Methods
function MyMethodDecorator(o: C, name: String): void {
trace(name);
}
class C {
[MyMethodDecorator]
public function f(): void {
}
}
Reserved Lexical Decorators
The following decorators are reserved, but can still be used if they do not directly appear as lexical references:
[Metadata()]
[Allow()]
[Warn()]
[FFI()]
- When applied to a class definition,
[Value]
is reserved - When applied to a class definition,
[DontInit]
is reserved - When applied to an enum definition,
[Flags]
is reserved
You can still use them if they are under a namespace or package, such as q.b.Metadata
.
Meta-data
Compile-time meta-data can be attached to any definition through the [Metadata()]
decorator. It can contain any kind of data.
Any added meta-data is erased at runtime.
package q {
[Metadata(x = '')]
public function f(): void {
}
}
Strictness
Shadowing variables
The "use shadowing"
pragma allows shadowing all variables in a scope:
{
'use shadowing'
var x = ''
var x = 0
}
Item Visibility
Items may specify a visibility modifier:
public
private
protected
internal
The default visibility is public
.
Standard Built-in Objects
The standard built-in objects are not yet documented, but they will be similiar to JavaScript ones.
Initial VioletDoc documentation for them will be generated soon. Here are the draft sources.
Runtime
This section lists some runtime details and general optimizations.
Single Item Insertion
The following call takes only one argument, so do not create an throwaway Array
for rest arguments:
array.push(v);
Constant Number Iteration
The following can be optimized by skipping the creation of the Generator
instance and skipping handling the step parameter.
for each (var i in Number.range(0, 10)) {
// procedure
}
String Representation
String
is either original or a slice of another one. When the type is auto boxed, this is not the case.
Auto Boxing of Value Types
Value types are interned on auto boxing. Primitive types like Number
are interned in more depth, for example, values under < 512 are looked up into a particular collection, String
s are divided into collections by length and Boolean
is simply binary. These internation collections should preferably consist of weak references whenever possible in the host environment.
Any Type Representation
- In native host environments, for the
*
type, aundefined
value is identified by variant 0,null
by variant 1 and anything else is an actualObject
reference address.
Union Type Representation
Union types are structural, however they are differentiated by member order. The first variant starts by the number 0.
// undefined = 0
// RegExp = 1
type UoR = undefined | RegExp;
// RegExp = 0
// undefined = 1
type RoU = RegExp | undefined;
Math methods
Things like min()
, max()
and clamp()
can be optimized according to given arguments ahead of time.
min()
with 2 arguments- Specialized types as it takes
*
- Specialized types as it takes
max()
with 2 arguments- Specialized types as it takes
*
- Specialized types as it takes
max()
ormin
with a list of numeric arguments of the same typeclamp()
with specialized types
Compiler Guide
Including and Excluding Sources
The compiler does not accept globbing patterns or specifying a directory for including sources recursively. This is so that you specify sources in the correct order for static property initialization.
Generally you must have an entry script including other scripts:
include './script1';
include './script2';