ActionScript
Compiler
(Started in July 2005 last updated on Jun 23 2008)
Summary
- This document license
- This document organization
- Input Tokens (lexical)
- Identifiers
- Numbers
- Strings
- Keywords
- Operators
- Comments
- Language basic instructions (Grammar)
- Program
- Declaration
- Packages
- Classes
- Functions
- Statements
- Block
- Break & Continue
- For
- Goto
- If
- Switch
- Throw and Try/Catch/Finally
- Variable
- While and Do
- With
- Expressions
- Compiler (what the compiler does)
- Optimizer
- How identifiers are being resolved
(scoping)
- ECMAScript basic instructions
- eval()
- parseInt()
- parseFloat()
- ECMAScript objects
- Object
- Boolean
- Number
- String
- Array
- Date
- Error
- Function
- arguments
- Math
- SWF basic instructions
- set()
- getVersion()
- setClipboard()
- eval()
- SWF instructions
- Timer functions
- MovieClip functions
- SWF objects
- Low level extensions (in Global package)
- System.accessibility
- Button
- Camera
- Color
- CustomActions
- Key
- LoadVars
- LocalConnection
- Menu
- Microphone
- Mouse
- MovieClip (or Sprite)
- NetConnection
- NetStream
- PrintJob
- Selection
- SharedObject
- Sound
- Stage
- TextField
- TextSnapshot
- Video
- XML
- SSWF extensions
- parseBoolean()
- Complex numbers
Copyright (c) 2005-2008 Made to Order
Software Corp.
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission
notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT
WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The document is divided in two main parts: the quick description of
how the language works (lexical and grammar) and a lengthy list of all
the objects available in the Flash Macromedia players.
Note that the description of the language is mainly for people who
already know how to write programs in either Javascript, C, C++,
ActionScript or any similar language. If you are not familiar with any
of these languages you certainly want to look into a tutorial for these
before to read on.
This document will especially list all the extra options available in
the SSWF implementation of the language. For instance, you can use a
label with the
break and
continue instructions which you
can't with the Macromedia implementation (as of version 7.x). There are
additional operators, functionalities in the grammar, different
pragmas, extension classes and functions... and this documentation!

[no kidding! no one else has this doc., right?]
The different tokens in the ActionScript compiler are recognized by
our lexer while reading some input text file.
The library only accepts USC-4 characters as input. If you need to
convert your input file, use the iconv(1) tool. It is capable of
converting almost any encoding to USC-4.
The recognized tokens are as follow:
- Identifiers
(A-Za-z0-9_$)
Identifiers can't start with a digit. The $ character should not be
used but by software generating ActionScripts. The case is significant.
So the identifiers Test and TEST are different.
- Numbers
Literal numbers include:
Type
|
Simplified
Lexical
|
Integers
|
[0-9]+
|
Hexadecimal
|
0[xX][0-9A-Fa-f]+
|
Floating Point
|
[0-9]+.[0-9]+[eE][-+][0-9]+
|
Infinity
|
Represents the positive infinity
|
NaN
|
Represents a value defined as a
"Not a Number" value
|
Octal
|
0[0-7]* — optional, use -o on
the command line or the use octal; pragma to have access to
this
feature
|
- Strings
It is possible to write strings. A string is written between single (')
or double (") quotes. A string can't include a new line character. You
can use the backslash character inside a string to include a special
character, including a quote. To write really long strings, you can use
the concatenation operator (+). The following table lists the available
backslash sequences.
Similar to strings, you can define a regular expression using backward
quotes (`). At this time, the SSWF implementation doesn't make use of
regular expressions because the Flash Macromedia players don't support
them. We may add an extension to support some basic regular expressions
at some point (so we can support the match (~=) operator).
Sequence
|
Comment
|
\0##
|
Insert a Unicode character (up
to 3 digits); The character is defined as an octal number
|
\b
|
Insert a backspace (0x08)
|
\e
|
Insert an escape character
(0x1B); this character is available only when the extended escape
sequences are supported
|
\f
|
Insert a form feed (0x0C)
|
\n
|
Insert a new-line (0x0A)
|
\r
|
Insert a carriage return (0x0D)
|
\t
|
Insert a tabulation (0x09)
|
\u####
|
Insert a Unicode character (4
digits); The character is defined as an hexadecimal number
|
\U########
|
Insert a Unicode character (8
digits); The character is defined as an hexadecimal number
|
\v
|
Insert a vertical tabulation
(0x0B)
|
\x## or \X##
|
Insert a Unicode character (2
digits); The character is defined as an hexadecimal number
|
\' or \" or \\
|
Insert ', " or \ as is.
|
other
|
Any other sequence generates an
error.
|
- Keywords
A Keyword is an Identifier representing a word used in the language.
The
following table list the keywords used in the ActionScript language:
Identifier
|
Comments
|
as
|
Compare two expressions for
similarity
|
break
|
Break a for(), do/while() loop
or a switch() statement. It can specify a label in which case it can
break a loop or switch() other than the current one.
|
case
|
Defines an expression to compare
with the expression defined in a switch() statement.
|
catch
|
Catch an error of a given type.
|
class
|
Starts the definition of a class.
|
const
|
Defines a constant variable.
|
continue
|
Restart a for(), do/while() loop.
It can include a label in which case it can restart a loop other than
the current loop. SSWF Extension: if the label references a switch(),
then the switch() is repeated after the switch() expression was
re-evaluated.
|
default
|
The default label to use in a
switch() statement. It can appear anywhere, but just once per switch
statement.
|
delete
|
Delete the specified instance of
an object.
|
enum
|
Define a list of numeric
variables with an automatic increment of 1.
|
extends
|
Used to extend a class
definition. One class can only extend one class; in other words
you can't have multiple inheritance like in C++ (the super instruction is one reason)
|
false
|
The boolean value false.
|
finally
|
The block to execute to
terminate a try block whether
an exception occurred or not.
|
for
|
Initialize, test and increment
loop definition.
|
function
|
Starts the declaration of a
function.
|
goto
|
Go to the specified label. This
instruction is recognized only if extended statements were enabled.
You can goto through any block except a function block.
|
if
|
Branch on a condition.
|
implements
|
Used to define a class that
implements the named interface(s).
|
import
|
This instruction allows you to
declare external packages and import them when you need them.
|
in
|
Check whether a property is
defined in an object (expression). In a for() statement, it can be used
to define a list of properties to walk through.
|
instanceof
|
To know whether an object is of
a specific type. |
interface
|
Starts the declaration of an
interface.
|
is
|
To know whether an object is of
a given type. |
namespace
|
The name space or name of a
package or class.
|
new
|
Operator used to create a new
instance of an object.
|
null
|
The value used to initialize an
undefined object reference.
|
package
|
Starts the definition of a
package.
|
private
|
The private attribute.
|
public
|
The public attribute.
|
return
|
End a function by returning the
result of the following expression. End a procedure (a function without
a return type).
|
super
|
Reference to the class this
object was derived from.
|
switch
|
Starts a switch()/case/default
statement.
|
this
|
The special reference to this
object. In an ActionScript, this is always available since at least you
are in a MovieClip. [to be confirmed]
|
throw
|
Raises an exception.
|
true
|
The boolean value true.
|
try
|
Create a protected, exception
wise, set of statements.
|
typeof
|
Defines the type of an
expression as a string.
|
undefined
|
The value used when you try to
access a variable which wasn't defined (set/assigned to) yet.
|
use
|
This keyword is used for pragma
definitions and scope (namespace) extension.
|
var
|
Declares a variable.
|
void
|
The special type void. Used to cast expressions and
declare procedures.
|
with
|
Extend the current scope with
the specified namespace.
|
while
|
Loop on a condition.
|
- Operators
The ActionScript recognizes many single or sequence of punctuation
characters as operators. The following table describes the available
operators. Note that some operators are keywords. Also, some operators
are only available when extended operators are turned on. These are
specified in the following table as well.
The SSWF implementation supports operator overloading. It is actually
used to make sure that the operators are used properly in your
scripts (since an operator overloaded is a function and a function
can be marked as intrinsic, we can use the language features to
make sure that the compile works properly).
The following shows you the definition of the additive operator for
integers:
intrinsic function "+" (i: Integer, i: Integer): Integer;
Note that the conditional operator (?:) and the keyword operators can't
be overloaded at this time (the new, delete, for+in should be available).
Also, whenever the compiler finds an overloaded operator
used in an expression, it will keep it as is if the function is marked
as intrinsic, otherwise it transforms the operator syntax in the tree
by a CALL of a member function.
At times, it makes more sense to define a function in the class defined
in the right operand. In C++ this is done by creating a friend function.
Since ECMAScript always defines functions for binary operators with two
parameters, there is no need for any special attribute:
function "&" (i: Integer, s: String): String;
This means writing
5 + "a" is resolved by this function.
The integer will be converted to a string which is then concatenated
to the other string.
Unary operators take one operand which needs to have its type defined
to the class name which includes the operator. Note that operators
can only be defined in a class to work properly.
The Netscape ECMAScript version 4 specification says that a few
operators should not be overriden. These include all the assignment
operators, "!=", "!==", "!", "||",
"&&" and "^^". At this time, the SSWF implementation doesn't
prevent you from implementing these operators. It is not unlikely
that I will add an error later unless you use a specific command
line option or pragma to enable overloading of non-intrinsic
operators.
Operator
|
Comments
|
Unary
|
~
|
Bitwise not
|
!
|
Logical not
|
+
|
Positive
|
-
|
Negative |
++
|
Increment
|
--
|
Decrement
|
delete
|
Deletes an instance
|
new
|
Creates a new instance
|
super
|
A reference to a class this
object was derived from
|
typeof
|
Determines the type of an
expression
|
void
|
Cast the result of an expression
to void (undefined)
|
[ ]
|
Reference, array indice(s),
array definition
|
( )
|
Expression grouping and arguments
|
{ }
|
Object definition
|
Binary
|
::
|
Scope
|
.
|
Access a property member
|
**
|
Power; the ** operator is
available when extended operators are accepted
|
*
|
Multiplication
|
/
|
Division
|
%
|
Modulo
|
+
|
Addition
|
-
|
Subtraction |
<<
|
Shift left
|
!<
|
Rotate left; the !< operator is
available when extended operators are accepted
|
>>
|
Shift right (signed, also called
arithmetic)
|
!>
|
Rotate right; the !> operator is
available when extended operators are accepted
|
>>>
|
Shift right unsigned (also
called logical)
|
<
|
Less than
|
<=
|
Less than or equal to
|
>
|
Greater than
|
>=
|
Greater than or equal to
|
~=
|
Match; the ~= operator is
available when extended operators are accepted [not implemented yet]
|
as
|
Check whether the left handside
expression is a member of the type specified on the right hand side |
in
|
Check whether a property is
defined in an object |
instanceof
|
Check whether an object is an
instance of a class |
is
|
Check whether an object is an
instance of a class |
==
|
Equal
|
===
|
Strictly Equal
|
!= or <>
|
Not Equal; the <> operator
is available when extended operators are accepted
|
!==
|
Strictly Not Equal
|
&
|
Bitwise and
|
^
|
Bitwise exclusive or
|
|
|
Bitwise or
|
&&
|
Logical and
|
^^
|
Logical exclusive or
|
||
|
Logical or
|
?<
|
Return the minimum; the ?< operator is
available when extended operators are accepted
|
?>
|
Return the maximum; the ?> operator is
available when extended operators are accepted
|
= or :=
|
Assignment; the := operator is
available when extended operators are accepted
|
**=
|
Power assignment; the **=
operator is
available when extended operators are accepted |
*=
|
Multiplication assignment
|
/=
|
Division assignment
|
%=
|
Modulo assignment
|
+=
|
Addition assignment
|
-=
|
Subtraction assignment
|
<<=
|
Shift left assignment
|
!<=
|
Rotate left assignment; the !<= operator is
available when extended operators are accepted
|
>>=
|
Shift right assignment
|
!>=
|
Rotate right assignment; the !>= operator is
available when extended operators are accepted
|
>>>=
|
Shift right unsigned assignment
|
&=
|
Bitwise and assignment
|
^=
|
Bitwise exclusive or assignment
|
|=
|
Bitwise or assignment
|
&&=
|
Logical and assignment
|
^^=
|
Logical exclusive or assignment
|
||=
|
Logical or assignment
|
?<=
|
Minimum assignment; the ?<= operator is
available when extended operators are accepted
|
?>=
|
Maximum assignment; the ?>= operator is
available when extended operators are accepted
|
,
|
List of expressions
|
Tertiary
|
?:
|
Conditional operator
|
- Comments
ActionScripts accept two types of comments like C/C++. The one line
comment starting with // and going to the end of the line and the long
comments introduced with /* and ending with */.
Note that either way, a comment is seen as a blank and thus the
following defines two identifiers:
Start/* a comment */Stop
The following is a simplified reference on how to use the basic keyword
in an ActionScript.
Note that this is very similar to Javascript and thus if you want to
have a tutorial, read a Javascript tutorial if you can't find an
ActionScript tutorial. Note that the Macromedia website had quite many
pages explaining how to use their objects and how to use their
language. This implementation is mostly compatible.
The language in SSWF is based on the ECMAScript version 4 as written by
Netscape in 1999 and enhanced until 2003. At the time of writing, the
documentation could be found here:
http://www.mozilla.org/js/language/es4/index.html.
In case it doesn't work anymore, try to search for "
ECMAScript 4 Netscape Proposal". This document is
based on the ECMAScript version 3 and ECMAScript version 4 (note
that version 4 of the ECMAScript is still being worked on).
- Program
Any ActionScript is a program. A program is composed of declarations
and statements. Statements can include expressions which are described
separately. When the program runs, the statements are executed. The
statements will make use of the declarations as required.
- Declarations
A declaration defines an element which late can be reused in different
statements or other declarations.
There are three major declarations: a package, a class and a function.
Note that there isn't really a variable declaration. Variables are
always being initialized and for this reason they are always viewed as
statements in our implementation. Non the less, most people will
consider those declarations. Yet, for the purpose of this
documentation, it won't be defined in this chapter.
Packages can
later be imported. This is how you create modules that you reuse as you
write more and more ActionScripts.
Classes enable you to declare
object definitions. These can be used to create object instances.
Functions are lists of statements to execute without having to
replicate these over and over again. We often see function definitions
in classes and packages.
- Packages
A package declaration goes like this:
<attributes> package <name> '{' ... '}'
A package can receive the following attributes:
Attributes
|
Comments
|
false
|
A package marked false will be
ignored. This can be used to create conditional parsing.
|
intrinsic
|
A package marked as
intrinsic offers a set of objects which are always available in the
executing environment. In case of the ActionScript, for instance, you
always have access to the MovieClip class and all of its functionality. |
true
|
A package marked true will be
included in the parsed script.
|
- Classes
A class definition can be used to create a new object, to extend an
existing object or to define one or more interfaces. The following
shows a class definition:
<attributes> class <name> [ extends <name> ] [ implements <name> {, <name>} ] '{' ... '}'
The
extends and
implements parts are optional. A
class can implement as many interfaces as it wants. It can, however,
only extend one other class. The order in which the
extends and
implements are given is important in
ECMAScript, it isn't for us (you can first use implements and then
extends). Also, the order in which the extends and implements are
defined isn't important because the compiler will always test all of
them to find the corresponding entry. Note that if two or more entries
match, then an error is generated (you can't have two fields with the
same name in two interfaces and inherit both and hope it works properly.)
A class can receive the attributes as defined in the following
table. Most of these attributes can individually be applied to the
members of the class.
Attributes
|
Comments
|
dynamic
|
Objects of that class can
dynamically receive new variable and function members.
|
enumarable
|
Whether the class members can be
enumerated.
|
explicit
|
When marked explicit, a member
can only be used with a qualifier.
|
false
|
A class marked false will be
ignored. This can be used to create conditional parsing.
|
final
|
The entire class can't be
extended.
|
intrinsic
|
A package marked as
intrinsic offers a set of objects which are always available in the
executing environment. In case of the ActionScript, for instance, you
always have access to the MovieClip class and all of its functionality. |
true
|
A class marked true will be
included in the parsed script.
|
Note that when you don't specify any
extends
name, a class automatically extends Object.
- Functions
A function definition is very useful to avoid writing very long
programs
in one stretch. Not only can a function be reused in a program, when
defined in a package, it can be re-used across projects. The following
gives the definition of a function:
<attributes> function [ <name> ] '(' [ parameter { , parameter } ] ')' [ ':' type ] '{' statements '}'
A function accepts the following attributes:
Attributes
|
Comments
|
abstract
|
The member function needs to be
declared in an extension of this class.
|
| constructor |
Defines a function member as a
constructor. |
enumarable
|
The function will be enumerated.
|
virtual
|
The function can be overloaded.
|
inline
|
The function statements will
automatically be inlined.
|
Functions can be unnamed. In general this happens when a function is
declared with a label or when they are to be assigned to an object. In
that later case, the assignment will provide a name to an object
member. That will be the name of the function. Note that when using a
function in this way, it can be assigned to multiple objects as
required.
The name of a function can be any valid identifier, which is the
default. It can be one of the keywords
get
or
set followed by an
identifier which defines a getter and setter function. And finally, the
name can be a string representing a valid ActionScript operator.
The getter and setter functions are actually functions used to simulate
a variable member that you can read and write to. This is useful
whenever a variable needs to be checked (i.e. only a value of 1 to 10
is valid, the setter function can make sure that you don't set the
variable to 25 for instance).
The use of a string is to declare a function which is an operator. This
should only be used in a class, thought it is possible to use it
outside too. Operators are declared like in C++, except for the name
which has to be a string. For instance, you can declare an addition to
a class named foo like this:
function "+" (right_hand : foo) : foo { ... }
The list of parameters defined for a function can be empty and as long
as required. Each parameter can have attributes as follow and when
calling a function the name of the parameter(s) can be used to make
sure that the right parameter receives the right value. The last
parameter can be defined as the rest (...) of the input parameters.
This uses the ellipsis. Note that the rest can be named (but I think we
won't be able to use that with the Flash player from Macromedia, but
I'm thinking there is a way to use the arguments variable instead.)
Parameter
Attributes
|
Comments
|
void
|
Can appear only by itself. Used
to mark a function as not having any parameters.
|
unprototyped
|
Used to specify that this
function doesn't have a prototype. This is used to allow a return value
definition (otherwise using the type Function is better) when a
variable is of type Function. Like void,
unprototyped can only
appear by itself.
|
...
|
Called rest, this defines a function which
can accept a variable number of parameters. The extract parameters can
be accessed using the arguments
array. A rest can be named:
MyFunc(a, b, ... rest) { ... }
|
const
|
Mark the parameter as a
constant. This means the input variable can't be modified within the
function.
|
in
|
This parameter is an input
variable. It is expected to be defined (doesn't have to be) and it
won't be modified for return by the function.
|
var
|
This is noise used to mark the
parameter name as being a variable.
|
out
|
The variable will be modified by
the function and its result is returned to the caller. An out variable
can't be defined as a constant. A parameter can be an in and out
variable at the same time. A function is not required to initialize an
out variable. Note also that this is an SSWF extension.
|
named
|
This is noise used to mark the
parameter as one which can be named whenever a function is being
called. We always authorize all the variables to be named when a
function is being called.
|
unchecked
|
Variables marked unchecked don't
need to be initialized when the function is being called. This is
useful whenever a function declares a variable without a default
initializer and the caller doesn't define a value. In this case, the
variable will be set to undefined.
|
The list of parameters of a function can be followed by a type
declaration. When no type is defined or the type is
void, the function is considered to
be a procedure (i.e. it can't return anything). When there is a type
other than
void, the function
must return a value of that type.
When a function is called, its statements are executed. At that time,
you have an array called arguments which can be used to access all the
parameters using an array notation. This is required if you use a rest
(...) in your list of parameters. Some other special variables can
eventually be set. These are
this
and
super.
- Statements
The statements are very similar to C/C++ and javascript. The following
are the statements supported by the SSWF implementation of
ActionScript. Note that expressions weren't included since these are
described below in chapter
4. Expressions.
- Block
attributes '{' ... '}'
Create a list of statements and definitions with the specified
attributes. Some statements such as
the
if(),
for() and
while() can be followed by one
statement. If you need more than one, then you need to enclose the
statements between curvely brackets.
Standalone blocks can be preceded by attributes. That is, a block
following certain instructions can't receive attributes. For instance,
the
try instruction doesn't
allow for attributes between the keyword and the opening curvely
bracket ({). Note that all the attributes which you can apply to a
block can also apply to other statements.
Attributes
|
Comments
|
false
|
When the attribute is defined as
false, then the block is no compiled.
|
true
|
When the attribute is defined as
true, then the block is compiled.
|
- Break
& Continue
break [ label ] ';'
continue [ label ] ';'
The
break and
continue instructions are used to
exit and repeat loops respectively. The
break can also be used to end a
switch statement and the
continue to repeat it (the latter
only if the continue has a label). Both instructions can be followed
by a label which allows to break or repeat any loop or
switch statement.
The label is optional in which case it is taken as being
default
and then the innermost loop is exited or repeated or the inner most
switch is broken (you can't repeat a switch() if you don't use a label).
Note that using the
continue
instruction with a label of a loop which isn't the innermost loop very
much acts like a
break of all
the inner loops until the loop to continue is reached.
The label specified after these instructions must directly precede the
instruction to be broken or continued.
The break and continue can be used between any boundary other than a
function. In other words, you can break a loop from a
try/catch
or a
with statement. All the necessary unwinding will be done
by the compiler as expected.
- For
for '(' expression ';' expression ';' expression ')' statements
for '(' expression in expression ')' statements
Create a
for loop. In the
first case, the 1st expression is expected to declare one or more
variable, the second expression compares the different variables and
the third computes the next value for the variables declared in the
first expression. Note that there is no tests to know what the
expression really are and thus they don't actually need to match the
default description.
The second version of the
for
instruction allows for loops over all the enumerable properties of an
object, over a range or a list of expressions.
As long as the second expression is true or the
for statement includes a property or
other item to run, the statements following the for will be run. If you
need more than one statement, put them in a block.
- Goto
goto label ';'
The execution continues at
<label>.
This is an SSWF extension as neither Javascript nor ECMAScript support
a
goto instruction.
SSWF supports a goto to jump from anywhere to anywhere except between
a function boundary (or within declarations in a function.) So you
stop excution in a try/catch and continue outside it. The compiler
will take care of the unwinding which in the case of a try/catch/finally
will run the finally statements first.
- If
if '(' expression ')' statements [ else statements ]
When expression is true, execute the following statements. If it is
false, execute the statements after the
else if it exists.
- Switch
switch '(' expression ')' [ with ['('] operator [')'] ] '{' case/default '}'
Compute expression, then search for a matching case. If none of the
expressions in the different case statements match, execute the default
statements, if any. Otherwise go after the switch statement at once.
Only the list of intructions within the one selected case are executed.
The statements of the following case don't just follow the statements
of the previous case (i.e. it is NOT like in C/C++).
The
with operator in a
switch() statement is an SSWF
extension. By default, a
switch() statement uses the strictly
equal comparison operator (===). Here you can specify which operator
you want to use: equal (==), strictly equal (===), match (~=),
in
as,
instanceof,
is, less (<), less or equal
(<=), greater (>), greater or equal (>=), mask (&).
You can use the
break instruction to exit a case statement right
away (in an if() statement for instance). The
break is not
required at the end of a case. It is implicit.
SSWF has another extension which allows a
continue statement to
repeat a
switch() statement when the
continue is used
with the label preceeding the
switch() statement. This repeats
the
switch() by first re-evaluating the
switch()
expression and then by searching all the cases again.
NOTE: what we are missing:
- A way to continue through to the next case statement
(as in C/C++); I propose the special statement:
false break; so just that one case can
continue or the use of a special attribute on the
switch statement: nobreak switch( ... ) ...
in which case all the case statements will continue
unless there is an explicit break.
- A way to continue the search of a valid case which can be useful
when the switch was used with the with operator and not
the strictly equal operator. I propose the special statement:
continue case; for case specific continuation
and the special attribute foreach on the switch statement:
foreach switch(...) with(...) { ... }.
For instance, the in operator used with ranges could be
used to match several overlapping cases. The search would still
be stopped by a usual break, continue, goto
and throw.
- A way to check all the matching cases before any of their
statements are executed. This is important in case the case
expressions aren't constants and some of the case statements
would change the following case value. This is similar to the
previous case, and will work when the switch statement
is used with the foreach attribute. We could also have
two other attributes serial and parallel which
would select the scheme to use here. At this time, SSWF only
supports the foreach attribute and assumes the user
wants parallelism.
- Throw
and Try/Catch/Finally
throw expression ';'
try '{' statements '}' [ catch '(' typed variable ')' '{' statements '}' ] [ finally '{' statements '}' ]
The
throw statement is used to
raise an exception. Exceptions can be caught using the
try instruction.
The
try block runs what is
called a protected block of statements. If an exception occurs while
running the statements in the block of statements following the
try keyword, then it won't stop the
script. Instead, the execution will continue with the corresponding
catch (i.e. the catch which variable
type is the same as the type of the exception expression). Either way,
the execution passes on to the statements defined in the
finally block.
Only one
catch will be
executed whenever an exception occurs. Each catch needs to define a
variable name with a different type. The last catch can defined just a
variable name in which case any other type will match. The comparison
for the type is done with the strictly equal operator (===) and the
typeof keyword.
Note that as an extension, SSWF accepts a standalone
try statement. In this case, SSWF
may have to add an empty
finally
for the loop to work with SWF players.
- Variable
var name [ ':' type ] [ '=' expression ] ';'
Define a variable and initializes it. Note that a variable declaration
is viewed as a statement because of the initialization. Thought, when
defined as a member of a class, you aren't supposed to have an
expression (thought we support it) and the variable is set to
undefined by default (when no
initializer is provided.)
The
type is an expression
which can be used to make sure that the variable is used properly. Note
that the Flash Macromedia player doesn't actually test for the variable
types and thus for now only
obvious
compile time errors will be reported. This will, however, be useful in
different circumstances like when a
try
instruction caught an exception and the proper
catch is searched (again, the player
doesn't support more than one catch, so we have to simulate the
multi-catch using the variable type at runtime).
- While
and Do
while '(' expression ')' statements
do statements while '(' expression ')'
Repeat the statements as long as
expression
is true. In case of the do/while(), the loop is executed at least once.
In case of just while(), it is executed only if the
expression is true at least once.
- With
with '(' expression ')' statements
Compute expression which needs to result in a type. Add that type to
the
current scope. This means you can avoid writing many references within
the statements following the
with
instruction.
- Expressions
Expressions are composed of all sorts of statements such as increment,
decrement, function calls, assignments, construction and destruction of
objects...
Expressions use operators as defined in the lexical (
Operators). The order of the operators as
defined in the lexical defines their priority. The following table
shows you in more detail the priority since some operators such as * /
and % share the same priority. Note that all the unary operators are
considered to all have the same priority even thought they don't
exactly are defined that way (i.e. in the expression ++a-- the
decrement is called first; in general, postfix operators are called
first). If you want to make sure of the order, then use parenthesis.
Operators
by Priority
|
Comments
|
~ ! + - ++ -- [ ] ( ) { }
this, number, string, regular expression
null, true, false, undefined, infinity, NaN
delete, new, super, typeof, void
variable name
(identifier)
|
+ as positive
- as negative
|
::
|
Scope
|
.
|
Member
|
**(1)
|
Power
|
* / %
|
Multiplicative
|
+ -
|
Additive
|
<< !< >> !>
>>>
|
Shift
|
< <= > >= ~=
as in
instanceof is
|
Relational
|
== === != <> !==
|
Equality
|
&
|
Bitwise And
|
^
|
Bitwise Xor
|
|
|
Bitwise Or
|
&&
|
Logical And
|
^^
|
Logical Xor
|
||
|
Logical Or
|
?< ?>
|
Min/Max
|
?:
|
Conditional
|
= := **= *= /= %= += -=
<<= !<= >>= !>= >>>=
&= ^= |= &&= ^^= ||= ?<= ?>=
|
Assignments
|
,
|
List
|
(1)
the power operator is the only one which works right to left:
a ** b ** c means a ** (b ** c) and
not (a ** b) ** c
I'm not defining here all the possible conversion happening in an
ActionScript because it would be very long. More or less, if you have
two numbers, normal mathematical arithmetic is used. If you have a
number of a string, the string may be transformed to a number if
possible, in which case, normal mathematical arithmetic is used. In all
other cases, string
arithmetic
is used.
You can
add two string
together in order to concatenate them. Our implementation accepts + and
& for concatenation which can be misleading since if the string can
be transformed to a number, it will be added (+) and not and'ed (&).
Only the typeof, +, &, [ ], ?<, ?>, relational and equality
operators work with strings. We may later add support for some
extensions such as * (repeat), positive (uppercase), negative
(lowercase), ~ (swap case), !< and !> (rotate).
Numeric arithmetic will be done with doubles unless both operands are
integers in which case 64 bits integers are used.
Operators can also be applied to objects whenever these overwrite the
operators as required (See the extension implementation of complex
numbers as
a good example). Otherwise, only a few operators act on objects: member
(.), array notation ([ ]), new, delete, super, typeof, instanceof, as,
in, is, ==, ===, !=, !==.
The following table describes what happens whenever the compiler
transforms the tree created by the parser. The idea is that the final
tree will be easily reusable by your own software to execute the
result or compile the code to binary (in case of Macromedia
ActionScript, we have to compile the result to binary).
There are two main things that the compiler will do for you:
- Check identifiers and resolve them (especially identifiers which
represent constants, these are replaced by the content of the constant
at once). Note that by default the compiler will be silent about
non-existent variable and function members of dynamic objects. This is
because dynamic objects can be grown to where it will not matter
whether the function exists at compile time. With a command line flag
to asc, you can get the compile to generate an error or a warning for
these identifiers.
- It will also transform different constructions to other types of
constructions so it is easier to implement the execution of the
resulting code. For instance, a switch()
+ statements can be transformed to a list of if()'s. This can be useful since
some cases can automatically be removed at compile time (i.e. switch() of an integer will never
match a case of a floating point with a decimal part).
Note that the compiler will make use of the optimizer to know whether
an expression is a constant expression or not and what its value is (of
interest to optimize in many different cases).
Also, when the compiler finds a symbol which it can't resolve until it
reaches a corresponding import (i.e.
foo.blah
matches
import foo), it loads
that import module. This means the compiler may use the lexer + parser
internally. In all cases, the import is resolved into a file on your
hard disk (see the -I option for the asc tool).
Construct
|
Transformation
|
Comments
|
Variable identifier in an
expression
(i.e. a = b + c)
|
The identifiers will point to
the
corresponding declarative node (this is scope dependent and it can be
pretty complicated.)
|
In this case there are two
things which the compiler tries to determine:
(1) it searches for the identifier 'a'; if it can find a var (or const)
declaration, then that one is used; if no such declaration is found,
then the compiler can be setup to generate an error; by default,
however, it will add a declaration automatically (i.e. the a = b + c becomes var
a = b + c)
(2) it searches for the identifiers 'b' and 'c'; if it finds a var
declaration, it links to it; if it find a const declaration, then it
replaces the identifier with the value of that constant
|
Member identifier in an
expression
(i.e. a.b.c)
|
The first identifier will point
to the corresponding class declaration and the second, third, etc. to
the corresponding member in that class. The member can be a member
function as well as a member variable.
|
Note that by default the
compiler will accept identifiers as members even if these are not
defined in any of the corresponding class unless the class is marked as
non-dynamic (in which case no additional members can be added to that
object at run time).
It is possible to ask for the compiler to either warn or err on such
problems.
|
const name = <expr>;
|
Checks whether that <expr>
is
indeed a constant expression. When that's the case, this definition
doesn't generate any statements in
the final output.
|
References to a compile time
constant will directly be replaced by the resulting
constant expression. This is why the constant doesn't generate a
statement in the
final output.
|
switch() + statements
|
temp = <switch expression>
if(temp === case1)
goto case1
if(temp === case2)
goto case2
...
if(temp === casen)
goto casen
goto default_statements;
statements of case1
statements of case2
statements of casen
...
statements of default
|
The transformation presented
here is over simplified. More or less, we compute the switch expression
once. We save it in a temporary variable which we reuse to compare to
each case expression. If it matches, then execute the corresponding
statements.
If the statements end with a break, then it will automatically add a goto statement to skip everything
up to after the default statement. Similarly, if there is a continue,
it
will goto to the
corresponding loop.
When there isn't a default label, the switch() statement doesn't have
any reaction and the goto
default_statements is replaced with a goto after_switch.
|
break <label>;
|
goto <label>;
|
A break is equivalent to a goto.
It will be easier to only implement one instruction such as a goto
rather than a break and a continue.
Note that a break used without a user label still is transformed to a
goto with an automatically generated label.
|
continue <label>;
|
goto <label>;
|
This is very similar to a break
except in the case of a for(),
it goes to where the 3rd expression is defined and run the
test as defined by the second expression. Also, in the case of a while() it will run the test again
before to repeat the loop.
|
for(<expr1>;;
<expr3>) + statements
|
<expr1>
$start$:
statements
$repeat$
<expr3>
goto $start$;
|
Repeat the statements forever.
Whenever the 2nd expression is empty (or constant and
resulting in true), this instruction is transformed to a loop forever program.
If the 2nd expression is a constant and it ends up being false, then
the entire loop is removed except for the first expression.
The compiler can be setup to warn whenever a loop forever is created by
putting a true or false constant in the 2nd expression.
|
for(<expr1>;
<expr2>; <expr3>) + statements
|
<expr1>
$start$:
compute <expr2>
if false then goto $done$
statements
$repeat$:
compute <expr3>
goto $start$
$done$:
|
Transform a for() loop into an
initialization with the first expression; a test with the second
expression (and the if() + goto
as required); run the statements; a computation of the third expression
and a goto back to the after the initialization.
A break without a label withing the for() statements generates a goto $done$; a continue generates a
goto $repeat$.
|
while(constant) + statements
|
$start$:
statements
goto $start$;
|
Run the statements forever if
the constant expression is true and remove everything if the constant
expression is false.
The compiler can be setup to warn whenever a loop forever is created
with a while.
|
while(<expr>) + statements
|
$start$:
compute <expr>
if false then goto $done$
statements
goto $start$
$done$:
|
Transform a while() loop into a test and an if() + goto().
This is particularly useful if your low level language only supports
the if() construct.
A break without a label within the while()
statements generates a goto $done$;
a continue generates a goto $start$.
|
do statements
while(<expr>);
|
$start$
statements
$repeat$:
compute <expr>
if true then goto $start$
|
The do is very similar to the
while except that the expression is only evaluated at the end. This
means the statements will always be executed at least once.
|
do statements while(constant);
|
$start$
statements
goto $start$
|
In case of a constant in a do + while, the loop either runs
forever or just once. The goto
$start$ is inserted if the constant is true.
|
if(constant) + if-statements [+
else else-statements]
|
if-statements or else-statements
|
Replace the if() statement with one or the
other part of the if()
whenever the expression is constant at compile time.
The compiler will warn on constant if()
since in most cases people don't want them (to remove an instruction,
one needs to use an attribute of false instead.)
|
conditional (?:) versus if()
statement
|
a ? b : c
if(a) b else c
|
We can, in general, change a
conditional into an if() and vice versa. However, there is no point for
the compiler to do such a transformation. The problem is that adding an
if() statement within an expression may not work for everyone, and
having an if() return expressions is not always practical... So for
now, I just leave these two instructions alone the way they are.
|
function () + statements
|
inline the statements
|
With a specific flag, you can
ask the compiler to replace function calls to user functions by the
direct statements of that function. This can be useful in some
circumstances, however, it usually won't be a good idea. By default,
only functions marked as inline
will be inlined if the compiler specify that it is compiling (rather than parsing for
immediate execution).
|
with(<expr>) + statements
|
temp = <expr>
change statements as required with <expr>.<identifier>
|
Transform a with into the long
syntax. The compiler will try its best at determining which variable
should be transformed.
|
try/catch/finally
(when only one catch supported)
|
the compiler creates one catch()
statement as follow:
catch(error) {
temp = typeof error;
if(temp == catch1-type) catch1-statements
else if(temp == catch2-type) catch2-statements
...
else if(temp == catchn-type) catchn-statements
else default catch statements
}
|
If only limited support for the catch() is available (i.e. version
3 of ECMAScript which only supported one catch with an untyped
variable) then the compiler can concatenate the catches as presented
here. Note that of course this is based on the proper functioning of
the typeof instruction.
|
try/catch/finally
(without exceptions support)
|
try statements
finally statements
|
If your implementation doesn't
support exceptions, then the try/catch/finally is transformed to just
the statements of the try block and the statements of the finally block
(if any). The catch blocks are removed.
|
with block & try/catch block
with a goto
|
...
goto_label = 3
goto $end_block$
...
$end_block$
from here we are not in the block anymore
...
if(goto_label == 3) goto label3;
...
|
Note that the block of
statements after a with(), a try, a catch() and
a finally all need to end
before you can go to another place. For this reason, the goto
instruction needs some special handling.
Note that the for(), while(), do/while() and switch() blocks are broken
in regular statements and thus they don't need this trick to be exited.
From within a function, it is an error to try to go to a label outside
the said function.
|
The ActionScript library of SSWF comes with an optimizer. In general,
once the user script was read with the Lexer and parsed with the
Parser, it needs to be compiled. In many places, the compiler expects
constants. Because a constant can be expressed as a complex expression,
we need an optimizer which can actually compute the expression and
return the result.
The optimizer will also look at statements that it can optimize. For
instance, a constant if() which is true is replaced by the statements
following the if(); a constant if() which is false is replaced by the
statements following the else and when no such statements exist, it
will return nothing (the if() is removed from the tree). [NOTE: this
may be moved to the compiler instead]
The following table shows you the different expressions and statements
that the optimizer recognizes and optimize whenever a, b and c are
constants. In some cases, we use x, y and z to represent an expression
which doesn't need to be constant.
Note that a constant variable is not automatically a constant for the
optimizer. The value of a constant variable may only be known at run
time. A constant for the optimizer is an integer, a floating point,
a string, true or false. Some other values, such as null, undefined
and NaN will be taken as constants in some circumstances and will
also be optimized.
On the other hand, whenever an expression calls an inline function
(a function which was marked as inline when defined), it will be
optimized by the compiler and not the optimizer. Also, only functions
which access public members can be optimized in this way (for Macromedia
Flash, that could certainly be releaved since the resulting objects
don't have a concept of private anyway).
Statement
|
Optimized
|
Comments
|
+a
|
a
|
Positive is simply removed on
intrinsic numbers
|
-a
|
(-a)
|
Negate, returns the negated value
|
!a
|
(¬a)
|
Logical not, returns the inverse
of toBoolean() on value
|
~a
|
(~a)
|
Bitwise not, returns value with
all of its bits inverted
|
++a or a++
|
(a + 1)
|
increment by 1
|
--a or a--
|
(a - 1)
|
decrement by 1
|
a ** b
|
(ab)
|
a power b
|
a * b
|
(a × b)
|
a multiplied by b
|
a / b
|
(a ÷ b)
|
a divided by b
|
a % b
|
(a ≡ b)
|
a modulo b
|
a + b
|
(a + b)
|
a plus b
|
a - b
|
(a - b)
|
a minus b
|
a << b
|
(a shl b)
|
a shifted left (b & 0x3F)
bits*
|
a >> b
|
(a shr b)
|
a shifted right (b & 0x3F)
bits* |
a >>> b
|
(a shr b)
|
a shifted right unsigned (b
& 0x3F) bits* |
a !< b
|
(a rol b)
|
a rotated by (b & 0x3F) on
the left* |
a !> b
|
(a ror b)
|
a rotated by (b & 0x3F) on
the right* |
a < b
|
(a < b)
|
true if a < b, otherwise false
|
a <= b
|
(a ≤ b)
|
true if a <= b, otherwise
false
|
a > b
|
(a > b)
|
true if a > b, otherwise false
|
a >= b
|
(a ≥ b)
|
true if a >= b, otherwise
false
|
a == b
|
(a ≒ b)
|
true if a is mostly equal to b, otherwise false
|
a === b
|
(a = b)
|
true if a is exactly equal to b,
otherwise false
|
a != b
|
(a ≠ b)
|
true if a is very much not equal
to b, otherwise false
|
a !== b
|
(a ≠ b) |
true if a is exactly not equal
to b, otherwise false
|
a & b
|
(a and b)
|
keep only the bits common to a
and b
|
a ^ b
|
(a xor b)
|
keep only the bits not common to
a and b
|
a | b
|
(a or b)
|
keep all the bits set from a and
b
|
a && b
|
(a ∧ b)
|
true if both a and b are true,
otherwise false
|
a ^^ b
|
(a ⊙ b)
|
true if either a or b is true
but not both, otherwise false
|
a || b
|
(a ∨ b)
|
true if a or b is true (either
one of them or both)
|
a ?> b
|
(a ≷ b)
|
return a if greater than b,
otherwise return b
|
a ?< b
|
(a ≶ b)
|
return a if less than b,
otherwise return b
|
a ? b : c
|
if(a) b else c
|
return b if a is true, otherwise
c
|
| * The
(b & 0x3F) is changed to (b & 0x1F) when b is a floating point
value. |
Whenever the compiler is invoked, it ensures that all the constructions
are valid (i.e. that you used a break within a loop or a switch) and it
searches for all identifiers which are not yet resolved (i.e.
b and
c in a statement such as
a = b + c).
In order to search for an identifier, the compiler uses the current
scope. This is determined by several factors:
- The current with()
instructions which are in effect
- The current use namespace
<name>; which are in effect
- The current enclosing block of directives
- The parent enclosing block of directives (repeat up to the
program block)
- The import instructions
For instance, in a class definition, variable members can be defined
before or after the different functions which uses them. Also,
functions can use each others wherever they are defined in the class.
The program and package blocks works in a similar way as the class
definitions. This means you can declare a class A which references
class B and declare class B after class A. This can be very useful
since in this way class B can also reference class A.
However, if package A requires a class defined in package B and vice
versa, you will need to make forward declarations instead. This is done
using the class as follow:
class A;
This defines the type A as a class (like in C++).
Whenever the search for an identifier goes through an
import directive, it checks whether
it matches. If it does, then the corresponding file is loaded, parsed
and checked in order to resolve the identifier. In the following
example,
Math.sin and
Math.PI match the
import Math directive.
import Math;
...
// sine of angle in degree
var sine = Math.sin(angle * Math.PI / 180.0);
Note that if a
use namespace
or
with() is active, then you
can also avoid using the package name
Math
each time you reference a
Math
function:
import Math;
use namespace Math;
...
var sine = sin(angle * PI / 180.0);
or:
import Math;
...
with(Math)
{
var sine = sin(angle * PI / 180.0);
}
The compiler will always try to resolve all the symbols. Symbols which
can't be resolved at compile time may still be valid at run time.
However, in many cases, the compile will err about those. One way to
avoid errors is to declare the dynamic functions and variable members
that you will use with an object or another. This way the compiler will
know about them and it won't have to guess whether your script is
functional or not.
This document was last updated on Jun 23 2008