Back to the SSWF project home page
Alexis' ActionScript Compiler ReferenceThis document license
Language References
The SSWF Setup File
How do I use the Javascript compiler with SSWF?
Comments
Literals (numbers, strings, etc.) and Special Keywords
Reserved Keywords
Attributes
Expressions and Operators
Functions
Control Flow Statements
Classes, Interfaces and Enums
Packages
Pragmas
Namespaces
Compiler Internals, Known Bugs and Frequently Asked Questions
History of this reference
Copyright (c) 2005-2009 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.
Thought the language for Flash is mainly devised by Macromedia, the actual reference is from Netscape. In version 7.x, the ActionScript compiler in Flash is actually a free version of the compiler from Netscape most certainly based on ECMAScript version 3 and tweaked by Macromedia to support some of the features of the following version. The current version (at time of writing) is based on a proposal by Netscape to the ECMAScript people. This is version 4 which isn't official yet (we're in 2005 and the proposal was written in 1999.)
You can find the ECMAScript 4 Netscape Proposal on the Mozilla website at this time. (Search for "ECMAScript 4 Netscape Proposal" in some search engine if the link below does not work anymore at the time you click on it...)
On that page, you have a access to a PDF which describes ECMAScript 4 as (supposedly) currently in the work by the ECMA people.
Another reference is of course the complete reference from Macromedia. You can find ActionScript v8.0 fully described. Note that includes many objects implemented by Flash developers and not actually implemented in the Flash Player. These objects are part of the mx package. Everything else should be available in the player (Sorry! I won't take the time to test that for you to make sure... we'll have to go and find problems as they arise.)
There are other sources for JavaScript, but only the Netscape Proposal is sensical in being used to write a compiler which is what I've done.
In order to accomodate the ActionScript support, SSWF now reads a setup file which includes some information about where to find the default packages and where to save the package database. It also includes a version, so we can make sure that we are reading the proper information.
The setup file is named sswf.rc and it is searched in order in this list of directories:
The file is composed of shell like variables (<name>=<value>). The table below lists the values currently understood by SSWF. The file can also include empty lines and lines commented out. Comments are like in a shell script, they start with a hash (#) and end with the end of the line.
version | Specify the SSWF version when this file was installed.
You may need to bump this version up and change some other
variables to use newer versions of the file. Example: version=1.7.3 |
required | 1.7.3 |
asc_path | Defines the path where the SSWF compiler will find
the system packages. In that directory, the compiler expects
to find three or four sub-directories: global,
system, native and the optional
extensions directory. In order to initialize the
packages automatically, these directories are expected to
include a file named as_init.asc. This file is
automatically loaded and compiled. It usually includes an
import statement used to automatically make the Global,
System and Native packages visible. This way, the end users
do not have to specify any import for the system to work. Example: asc_path=/usr/share/sswf/scripts |
required | 1.7.3 |
asc_db | Specify a fullpath to the package database file.
It needs to be somewhere you can read and write a
file. If you are creating a system for multiple users,
then make sure you use a sub-directory in the users home
directory. This is important since each user may have
different packages and these may not be available to all
the other users. Also, all users need to have write access
to the package database file. You can specify a path which is not a fullpath. For instance, you can use asc_db=sswf/asc_database.db . This
is fine, but anywhere you use SSWF, you will need to have
a sub-directory named sswf.A better way, is usually to ask the users to create a sub-directory named sswf (or .sswf) in their home directory (i.e. mkdir ~/.sswf ) and then to setup this
file to make use of that directory:
asc_db=~/.sswf/asc_database.db . The ~ will
automatically be replaced with the user's home directory.The name of the database file can be anything. It is suggested that you use asc_database.db though (the default). Example: asc_db=tmp/sswf-db.txt |
~/.sswf/asc_database.db | 1.7.3 |
The actionscript compiler is actually in a library. The SSWF compiler
links against that library and thus includes the functionality directly
inside its language. Whenever you need to write an actionscript in
an SSWF file, you now can use the actionscript
object.
do action { actionscript test { // do something useless var b: Integer, c: Integer, d: Integer, e: Integer; var a: Integer = (b + c * d) ** e; }; };
The scripts themselves are mostly Javascript compliant. Some features are either not yet implemented or may work in a slightly different way than expected, but in general, it will work the same. (Most of you will be just fine. As long as you do not try all the most advance features of the language... you know!)
So, in order to learn the basics, I suggest that you read Javascript manuals. That will give you most of what you need to understand the basic flow control statements, expressions, the exception hanlding and the global classes: arrays, strings, numbers, dates, functions, math, boolean and errors. All of this is described in this documentation but only briefly. This documentation isn't a tutorial.
On the other hand, in this documentation you will find what is and what is not working in this implementation. Also, there are extensions available in the SSWF version which you may want to use in your scripts. For instance, you can use the ?< and ?> operators to retrieve the maximum or minimum of two or more expressions. Similarly, the SSWF version supports overloading of operators. Here too, we went beyond the specification and we authorize nearly all the operators to be overloaded.
Finally, this documentation describes all the objects available in the SSWF implementation: the Global objects (such as Integer and String), the System object specific to Flash and the Native objects which are used to manipulate all the objects available in Flash such as sprites (called movie clip?!), buttons, cameras, colors, etc. That you can also find on the Macromedia website.
Please, refer to the actionscript object in the Reference to the Scripting language for SWF for more information on how to include an actionscript in your SSWF scripts.
ActionScripts which include class or interface definitions can't be defined within a sprite. This is because a sprite can't be defined as a child of another sprite (it can only be referenced and viewed as a child, not defined). And internally, classes and interfaces are sprites. However, SSWF takes care of extracting these classes accordingly and thus as an end user you can declare anything anywhere it is legal in Javascript.
This implementation of ActionScript supports two types of comments.
The regular multiline C comment introduced by /* and ending with */. Note that you cannot include a comment in another comment (as per the ECMAScript documentation.) Thus, the first */ found closes a comment.
/* my comment can span on multiple lines */
The regular one line C++ comment introduced by // and ending with the end of the current line. Note that all the characters are ignored in that comment and thus another comment introducer (// or /*) will be ignored.
// a one line comment
If you need to comment out a block of instructions between { and } then you can simply mark them false. This is the best way to comment out a whole block whether it includes C comments or not.
false { if(quit) { exit(); } }
This implementation of ActionScript supports the literals as described in the table below.
__CLASS__ String |
The special identifier __CLASS__ is automatically transformed by the compiler into the name of the class in which it is found. It is an error to use it outside a class. It works when used in a sub-interface of a class. | 1.7.4 | ||||||||||||||||||||||||||
__DATE__ String |
The special identifier __DATE__ is automatically transformed by the compiler into a string representing the date at which the code is being compiled. This can be used later as a time stamp. Note that if you use dynamic compiling, it may not be very useful. For Flash, it will give you an indication of when it was compiled. | 1.7.4 | ||||||||||||||||||||||||||
__DATE822__ String |
The special identifier __DATE822__ is automatically transformed by the compiler into a string representing the date according to RFC-822 at which the code is being compiled. This can be used later as a time stamp. Note that if you use dynamic compiling, it may not be very useful. For Flash, it will give you an indication of when it was compiled. | 1.7.4 | ||||||||||||||||||||||||||
false Boolean |
The boolean value false. It is also often represented by the number 0. See the value true for more information. | 1.7.3 | ||||||||||||||||||||||||||
__FILE__ String |
The special identifier __FILE__ is automatically transformed by the lexer into the name of the file currently being parsed. This is the same as __FILE__ in the C/C++ preprocessor. | 1.7.4 | ||||||||||||||||||||||||||
__FUNCTION__ String |
The special identifier __FUNCTION__ is automatically transformed by the compiler into the name of the function in which it is used. It is an error to use it outside a function. Only the inner most function name is returned. | 1.7.4 | ||||||||||||||||||||||||||
__INTERFACE__ String |
The special identifier __INTERFACE__ is automatically transformed by the compiler into the name of the interface in which it is found. It is an error to use it outside an interface. It works when used in a sub-class of an interface. | 1.7.4 | ||||||||||||||||||||||||||
__LINE__ Integer |
The special identifier __LINE__ is automatically transformed by the lexer into the name of the file currently being parsed. This is the same as __LINE__ in the C/C++ preprocessor. | 1.7.4 | ||||||||||||||||||||||||||
__NAME__ String |
The special identifier __NAME__ is automatically transformed by the compiler into the fully qualified name of the function, class, interface and package in which it is used. When used outside all of these, then it returns an empty string. Only the inner most package name is returned. This is used with the trace() special command. | 1.7.4 | ||||||||||||||||||||||||||
null Object |
The null value is used for variables which are used as references to objects. This marks the references as not used. If you set a variable to null and that was the last variable referencing an object, it will automatically delete that object (I think... TBP -> to be proven!). | 1.7.3 | ||||||||||||||||||||||||||
__PACKAGE__ String |
The special identifier __PACKAGE__ is automatically transformed by the compiler into the name of the package in which it is used. It is an error to use it outside a package. Only the inner most package name is returned. | 1.7.4 | ||||||||||||||||||||||||||
super Object |
The special identifier super is a
reference to the super class instance. That's the class we are
derived from. For instance, in the following, super references
to class A:
class A { function test() {} } class B extends A { function test() { super.test(); } } Note: if you are interested to know, this is the reason why you cannot have more than one extends on a class. There are several ways to fix this problem, but since Macromedia Flash does not support more than one extends (and the ECMAScript reference also mentions just one,) we will stick with it the way it is. |
1.7.3 | ||||||||||||||||||||||||||
this Object |
The special identifier this is a reference to an
object. It is available in functions which are dynamically
declared as members of an object or defined in a class. Note: in Flash, this is always defined because wherever you run a script you will always be in some object. The primary environment is the _root which is a MovieClip object (a sprite.) |
1.7.3 | ||||||||||||||||||||||||||
__TIME__ String |
The special identifier __TIME__ is automatically transformed by the compiler into a string representing the time at which the code is being compiled. This can be used later as a time stamp. Note that if you use dynamic compiling, it may not be very useful. For Flash, it will give you an indication of whem it was compiled. | 1.7.4 | ||||||||||||||||||||||||||
true Boolean |
The boolean value true. It is also often represented by the number 1. However, if you try to call a function with a pre-defined prototype, you will need to use the correct type and thus a boolean value if need be. | 1.7.3 | ||||||||||||||||||||||||||
undefined undefined |
The undefined value is used anywhere a reference is left undefined. For instance, if you mark a function with some parameters which do not need to be passed by the caller, these parameters will be set to undefined unless the caller defines them. | 1.7.3 | ||||||||||||||||||||||||||
__UNIXTIME__ Integer |
The special identifier __UNIXTIME__ is automatically transformed by the compiler into an integer representing the time at which the code is being compiled. This can be used later as a time stamp. Note that if you use dynamic compiling, it may not be very useful. For Flash, it will give you an indication of whem it was compiled. | 1.7.4 | ||||||||||||||||||||||||||
__UTCDATE__ String |
The special identifier __UTCDATE__ is similar to __DATE__ using Universal Time Coordinate. | 1.7.4 | ||||||||||||||||||||||||||
__UTCTIME__ String |
The special identifier __UTCTIME__ is similar to __TIME__ using Universal Time Coordinate. | 1.7.4 | ||||||||||||||||||||||||||
.+ identifier |
An identifier is defined as all the non-punctuation characters and thus it is a pretty large set. The usual identifiers are defined as letters, digits and underscores. It cannot start with a digit. | 1.7.3 | ||||||||||||||||||||||||||
[0-9]+\.[0-9]+[eE][+-][0-9]+ numbers |
The syntax for numbers is a string of
digits with an
optional decimal point and exponent. The use of the
decimal point transforms the number in a floating point.
Note that you do not need any digits before the decimal point
in which case it is considered as being zero (.9 and 0.9
are considered the same.)
A floating point number can optionally end with an
exponent (at this time, you cannot use the exponent
syntax for integers). Integers can be specified in
decimal (the default) or hexadecimal when they start
with 0x or 0X in which case digits and letters from
A to F can be used. When the octal pragma
option is turned on (by default it is off as per the specification),
you can start a number with a zero and continue with
digits 0 to 7 to form an integer in base 8. Note 1: this syntax does not allow for a number to be followed by a member operator; we may fix that at a later date, though you can still put the number between parenthesis: (5).ToString()
will work.Note 2: this syntax also does not allow for the compiler to understand something like this: 5.....2 ,
without a bit of luck. In this case it works. It finds
the floating point number 5., then the rest operator
(...) and finally the decimal number 0.2. Still, you
should use spaces to separate floating point numbers
and the rest or range operators. In this case:
5..2 , the compiler cannot see 5 .. 2 as
one would eventually expect. |
1.7.3 | ||||||||||||||||||||||||||
"..." or '...' String |
Define a literal string between a set
of single or double
quotes. Inside the quotes you can use a backslash to escape
a quote character, a blackslash or insert a control character
using either a letter or a value.
|
1.7.3 | ||||||||||||||||||||||||||
`...` regular expression |
The default ECMAScript definition declares regular expressions between / and /. There are several problems linked with that syntax, the most obvious is the divide sign which looks very much alike. The solution is to see any / as a divide sign if possible. This is complicated to say the least. The other problem is that a mistake can change the start of the sequence in a comment introducer /* ... and that too can be really hard to detect. It is an invalid regular expression, but it could happen. My solution is to use backward quotes for regular expressions. This simple trick resolves all of these problems. At this time, SSWF does not really do anything with regular expressions, but the literal is already supported for future compatibility. See the match operator for one usage example. The content of a regular expression is exactly the same as the content of a string. You can use the same escape sequences. | 1.7.3 | ||||||||||||||||||||||||||
[ <expr>, ... ] array declaration |
Declares an array inline. This syntax allows you to define an array with the values as defined by the list of expressions defined between the [ and ]. It is valid to declare an empty array ([]). The result of this expression is a reference to the newly created array. You can save arrays in variables or use them as function parameters. | 1.7.3 | ||||||||||||||||||||||||||
{ <label> : <expr> , ... } object declaration |
Declares an object inline. This syntax allows you to define an oject with properties and their values as defined by the list of labelled expressions defined between the { and }. The result of this expression is a reference to the newly created object. You can save inline objects in variables or use them as function parameters. | 1.7.3 |
The language has a set of reserved and special meaning keywords. Reserved keywords are recognized by the low level lexer and they cannot be used as identifiers anywhere. The special meaning keywords can however be used as regular identifiers in places other than where they have that special meaning.
The ECMAScript language reference says that an identifier with an
escape sequence cannot be a keyword. I do not see the point. Escape
sequences are being parsed at the time the text is read and if
the resulting identifier is a reserved keyword, it is reserved in
SSWF. (Also, what is the point of having escape sequences in
identifiers? I would think that you can use UTF-8 or Unicode if
you want to write identifiers in your own language and not have
to use escape sequences anywhere. A variable name such as:
être
will never be a keyword.)
abstract (*) | This is just noise. It is an attribute to a function to make sure you know that it is on purpose that no body was defined. This is not a keyword in SSWF, just a function attribute. You cannot use this attribute and declare a function body or you get an error. | 1.7.3 |
as | The 'as' operator. | 1.7.3 |
break | Break a for, while or do loop. Break a switch statement. Note that you can use the autobreak attribute on switch statements so it automatically breaks between cases (except empty ones, as in: cases not followed by any statements but immediately with another case.) With a label you can directly break to the end of the named loop or switch. | 1.7.3 |
case | Defines one case in a switch statement. Note that multiple cases one after another can be used to enter the same list of statements. In this special case, even the autobreak switch attribute has no effect. | 1.7.3 |
catch | Catch exceptions. | 1.7.3 |
class | Defines a new class (also called type). | 1.7.3 |
const | Defines a constant variable. SSWF accepts 'var' right after 'const'. This is not in the ECMAScript specification. But it doesn't break anything. | 1.7.3 |
continue | Repeats a for, while or do loop. With a label, you can
also repeat a named loop (it will break
all the inner loops and then repeat the named loop). SSWF enables you to continue a switch statement. For a switch statement, the continue statement must use a label. It will continue testing the switch cases. If no other case statement matches, then the continue acts like the break statement. Without a label, the continue acts as expected in ECMAScript: it continues the loop it is defined in. |
1.7.3 |
debugger (*) | Send some information/commands to a debugger. | n.a. |
default | The default statements to execute in a switch statement when none of the case statements matched. Also the label of a break or continue statement in order to reference the current loop (it is not required). | 1.7.3 |
delete | Delete an object. | 1.7.3 |
do | Defines a do ... while() loop. | 1.7.3 |
else | Defines the statement to execute when an if() expression is false. | 1.7.3 |
enum | SSWF supports this extension which defines an enumeration type. Each entry represents a value which is automatically incremented if not assigned. Also, the assigned value can be dynamic! (Defined as a non-constant expression only known at runtime.) | 1.7.3 |
export (*) | SSWF does not define this keyword yet. I'm not too sure what it could be for. In Javascript you do not export, you just define packages. | n.a. |
extends (*) | A class can extend another using this keyword. | 1.7.3 |
false | The literal value false. | 1.7.3 |
finally | The part to execute before exiting a try block whether an exception was received or not. | 1.7.3 |
for | Defines a for and for each loop. | 1.7.3 |
function | Declares a function. | 1.7.3 |
get (*) | This identifier has the special meaning of creating a getter function when used within a function name declaration. It needs to be followed by another identifier which represents the actual name of the getter. | n.a. |
goto | Go to a user defined label. Note that this is an SSWF extension. | 1.7.3 |
if | Starts an if/then[/else] statement. | 1.7.3 |
implements | List interfaces implemented by this class. | 1.7.3 |
import | Specify system and user extension modules to import. | 1.7.3 |
in | The 'in' operator in expressions and for loops. | 1.7.3 |
instanceof | The 'instanceof' operator in expressions. | 1.7.3 |
interface | Defines a class which is not derived from Object. We can call this a standalone class, however you cannot create an object from just an interface definition. | 1.7.3 |
is | The 'is' operator in expressions. | 1.7.3 |
namespace | Defines a new namespace. Makes a namespace visible. | n.a. |
native (*) | This is marked as a possible extension keyword. To me it looks like an attribute and it does not need to be a keyword in SSWF. | n.a. |
new | Create a new object. | 1.7.3 |
null | The 'null' literal. | 1.7.3 |
package | Starts the declaration of a package. | 1.7.3 |
private | Marks the following declaration as private to this class. This is an attribute, however it is viewed as a keyword so it cannot be used as a variable or a function name. | 1.7.3 |
protected (*) | Marks the following declaration as protected to this class. This is not a keyword in SSWF. It can be used as an attribute and will mark variables and functions as only accessible from this class and extensions of this class. | 1.7.3 |
public | Marks the following declaration as public to this class. This is an attribute, however it is viewed as a keyword so it cannot be used as a variable or a function name. | 1.7.3 |
return | Returns a value from a function. | 1.7.3 |
set (*) | This identifier has the special meaning of creating a setter function when used within a function name declaration. It needs to be followed by another identifier which represents the actual name of the setter. | n.a. |
super | Reference to the super object of this object. | 1.7.3 |
switch | Starts a switch statement. | 1.7.3 |
synchronized (*) | Defines a variable or function which can be accessed only by one thread at a time (this is really just a guess, I have no idea what this is for). At this time SSWF does not recognize this statement since it could most certainly be an attribute and thus does not need to be a reserved keyword. As far as I know, "threads" under Flash are run serially anyway. A sprite is considered to be a thread. | n.a. |
this | Reference to the object of which a function member is being executed. | 1.7.3 |
throw | Throws an exception. | 1.7.3 |
throws (*) | This is a keyword reserved for future use in ECMAScript. It looks to me that could very well be an attribute to a function to indicate that it may throw an exception so SSWF does not define this as a keyword. | n.a. |
transient (*) | The transient attribute will only be an attribute and thus not a keyword in SSWF. | n.a. |
true | The literal value true. | 1.7.3 |
try | Runs a set of statements safely (with guards). In case an exception occurs one of the following catches will be executed. To clean up, the finally statements are executed whether an exception occured or not. | 1.7.3 |
typeof | This statement returns the name (as a string) of the type of some arbitrary object. | 1.7.3 |
undefined | ECMAScript version 4 does not define this identifier as a keyword. It is a keyword in SSWF. | 1.7.3 |
use | Defines a pragma or starts using a given namespace. Some pragmas are available in version 1.7.3. Namespace are not yet supported by the compiler (the parser accepts them though.) | 1.7.3 |
var | Starts the definition of a variable. | 1.7.3 |
void | Marks an expression as void. [not too sure why we need void and Void; SSWF sees both as the same type] | 1.7.3 |
volatile (*) | The volatile attribute will only be an attribute and thus not a keyword in SSWF. | n.a. |
while | Creates a while loop. | 1.7.3 |
with | Creates a block of statements which can access the given object members without using its reference each time. | 1.7.3 |
Definitions in your code can receive a list of attributes. Definitions are functions, blocks of declarations1, packages, classes, variables, etc.
1a declaration is a definition or a statement.
All the definitions will always accept true and false. A definition marked true (the default when not marked either true or false,) means that the definition is to be used. A definition marked false, is a definition which needs to be ignored. This allows for dynamic compiling similar to a pre-processor. Whenever you include a package, using the true and false attributes, you can turn on and off different features. For instance, you can have a debug and a release version of some code. In the example below, the do_something() function writes some extraneous messages in a console when attr_debug is set to true.
// NOTE: this example is not yet functional (as of v1.7.3) // in some package package that_package { function do_something(a, b, c) { ... attr_debug { echo("We came through here"); } ... } } // in some program file const var attr_debug := true; const var attr_release := !attr_debug; ... import that_package; ...
In this example, we define the value for attr_debug to true. Then the echo() function is compiled. [Note: an external package will not look outside itself for variables; that's a problem for this pre-processor! I will look into a fix in a later version of SSWF to support this mechanism.]
The attributes, by definition, are a list of names put in front of a definition and understood by the system. They can be used directly or put in a constant variable. When defined in a variable name, that name can be used instead of the attribute. In effect, it makes it a dynamic attribute. Note that a variable can reference another variable. All the variables need to be constants. The name of the variables cannot be the name of any of the currently supported attributes. The special true and false attributes can be negated with the logical not operator.
The attributes understood by such and such definition are listed along that definition documentation. The following is just a list of all the attributes currently understood and which definitions understand it. The ones underlined are also reserved keywords.
abstract | member functions | n.a. |
array | all functions | 1.7.3 |
autobreak 1 | switch statements; forces a break between each case (except empty ones, as in: cases without statements) | 1.7.3 |
constructor | member functions | 1.7.3 |
dynamic | classes, variables and functions | 1.7.3 |
enumerable | class members (variables and
functions) visibility;
see for (enumeration)
|
1.7.3 |
false | all definitions | 1.7.3 |
final | classes, member functions and variables | 1.7.3 |
foreach 1 | switch statements; assumes a continue on each case | 1.7.3 |
internal | functions, classes, interfaces and variables inside a package | 1.7.3 |
intrinsic | packages, classes, interfaces, functions, variables | 1.7.3 |
nobreak 1 | switch statements; this is the default which is to not automatically break between cases (fallthrough) | 1.7.3 |
private | member functions and variables of packages and classes | 1.7.3 |
protected | member functions and variables of classes | 1.7.3 |
public | member functions and variables of packages and classes | 1.7.3 |
static | member functions and variables of classes | 1.7.3 |
true | all definitions | 1.7.3 |
unused | all functions | 1.7.3 |
virtual | member functions of classes | 1.7.3 |
1 switch statements get their attributes defined right before their block of statements; for instance one can write the following:
switch(expr) with(<) foreach { case 0: // executed when 'expr < 0' is true ... case 1: // executed when 'expr < 1' is true ... case 2: // executed when 'expr < 2' is true ... default: // always executed ... }
In this example, if expr is 1, then the statements of case 1, case 2 and default are all executed. To avoid executing default after case 2, use a break statement. (similarly, you can break any one case to avoid the foreach effect.)
This implementation of ActionScript supports the operators as descibed in the table below. Note that some of these operators are extensions to the standard. You can make sure not to use them using a pragma to turn them off. You will recognize these extensions by the asterisk following the SSWF version availability such as in: 1.7.3 (*).
The following table gives the operators in priority order. Operators with a higher priority appears first in the table. A higher priority is used first in an expression without the need to use parenthesis for proper grouping.
For instance, in a + b * c
, the compiler
generates b * c
and then adds a
to the
result.
When you use one or more operators with the same priority, it usually will apply the first operation first (the one most on the left). A few operators have a right priority such as the power operator. This means the last operation is executed first.
For instance, the expression a ** b ** c
is equivalent
to a ** (b ** c)
.
The SSWF Availability column also include a flag to mark operators which can be overloaded. To overload an operator, create a function with a name written in a string that is the operator that you want to overload. For instance, the additive operator for the integers is defined like this:
intrinsic function "+" (l: Integer, r: Integer): Integer;
Note that if you define your own class and want to override an operator
you cannot specify intrinsic
. It will usually reference
objects of the same class, though this is not a requirement since operator
functions are automatically considered static.
<expr> -- post decrement |
18 | Decrement the expression by one. If the expression is a variable name, the content of the variable is decremented. The expression result is the expression value before it is decremented. Note that if the expression is not a variable or an object, then this operator has no effect. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ++ post increment |
18 | Increment the expression by one. If the expression is a variable name, the content of the variable is incremented. The expression result is the value before it is incremented. Note that if the expression is not a variable or an object, then this operator has no effect. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ( <params> ) function call |
18 | An expression followed by parenthesis becomes
a function call. The expression needs to be resolved
as an identifier naming a function. The
function can be defined locally, globally or as a
class member. If the name is resolved as a variable
name being a reference to an object of a class that
has the "()" operator overloaded, then that operator
function is called with this set to that variable.
For example:class Foo { ... function "()" (q: Number) { ... } ... }; ... var t: Foo = new Foo; ... t(53.2); // calls the "()" function // this = t and q = 53.2 ... The <params> defined between the parenthesis in this definition represents a list of expressions separated by commas and used as parameters to the function being called. This list can be empty. All functions should be defined with a prototype. This means the type and number of parameters that you can pass to a function are predetermined and need to match the prototype exactly. If one or more functions with the same name are found but none of them match the prototype, then the compiler fails. If the call expression is defined in a function, that function is named the caller function. Similarly, the function being called is named the callee function. When the caller function has a rest (...) parameter, it can be passed down to the callee function using the rest keyword as in: function func(a, b, ...) { sub_func(a + 3, ...); } This has the effect of passing all of the parameters specified after the first two (a and b in this example) to the function func() down to the function sub_func() (not available in 1.7.3, at least not yet 8-). SSWF supports the naming of parameters. This means you can write the name of each parameter followed by a colon and then an expression representing the value given to that parameter. This enables you to specify the parameters in whatever order you like. Contrary to the ECMAScript documentation, in SSWF, you do not need to specify 'named' for any of the function parameters, you do not need to specify all the parameters by name even after you started to use a named parameter, and you do not need to have default values for any parameter in the function prototype. The compiler can very easily figure all of that out by itself. |
1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ( <expr> ) implicit cast |
18 | An expression followed by parenthesis becomes
a cast whenever the expression represents a type.
This has the effect of the as operator.
For example:var a:Integer := Integer(x);is equivalent to var a:Integer := x as Integer; |
1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> [ ... ] array or property access |
18 | The first expression is expected to be either an array or an object. In the first case, you can define a list of expressions between the square brackets ([]). When an object is being accessed, only one expression is expected which will be a string representing the name of a property of that object. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> . <expr> member |
18 | The period is used to access a member of an object or a package. This is considered an operator thought at times it does not really look like it. The second expression is usally an identifier, but it is not a requirement (Javascript is very dynamic!). When it is not an identifier the result will only be known at run time. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> :: <expr> scope |
18 | The scope is a way to group functions, variables and classes which can then dynamically be selected. It is somewhat similar to using a preprocessor in C/C++. The first expression is the name of the scope. The expression on the right is the name of the function, variable or class to access. Internally, there are many different scopes defined such as public, private, internal, protected, intrinsic, true, false, etc. Please, see the chapter Namespace & Scope for more information. Only some internal scopes are currently implemented. If it looks like there is a need for a real scoping support, I will look into add that in the language. It could be of interest in a world such as a browser so you can scope using the name of the browser (i.e. the same name function could be scoped for Netscape, Internet Explorer or Opera. Put that name in a variable, and the language automatically picks the correct function at run time!) | n.a. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
( <expr> ) grouping |
17 | Group expressions to force the order in which they need to be evaluated. In most cases, you can define a list of expressions between parenthesis. Note that an identifier used between parenthesis automatically becomes a reference to a variable whereas, used directly, it can be a direct name (i.e. a.b(); b is a direct member name, wheras in a.(b)(); b is viewed as a variable name or a getter function and what it returns becomes the member name.) | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
+ <expr> positive |
17 | The positive operator is mainly for completeness. It may be used to convert any expression to a Number. However, you should really use the ToNumber() function for that purpose. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
- <expr> negative |
17 | Negates the expression. This is equivalent to 0 - <expr>. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
~ <expr> bitwise not |
17 | Transforms all the bits of the number from 1 to 0 and vice versa. This is similar to <expr> ^ -1 | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
! <expr> logical not |
17 | If the expression is true, return false otherwise return true. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-- <expr> pre decrement |
17 | Decrements the expression by one. If the expression is a variable name, the content of the variable is decremented. The expression result is the decremented value. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
++ <expr> pre increment |
17 | Increments the expression by one. If the expression is a variable name, the content of the variable is incremented. The expression result is the incremented value. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new <expr> ( ... ) create an object |
17 | Creates a new object. The expression defines the name of
a class of which an object is to be created. The result
is a reference to the newly created object. You can later
use that reference to call function members and read/write
variable members of that object. The expression can be
a function call. In that case a corresponding constructor
will be called before the new expression returns.
Note that the parenthesis are not required if there is
not a constructor requiring parameters. You can create a
copy of an object using the source object as a parameter
to the constructor as in:
o:Object; o := new Object; ... copy:Object; copy := new Object(o);
|
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
delete <expr> destroy an object |
17 | Destroys an object previously created with the new operator. The expression is a reference to the object. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
typeof <expr> type of |
17 | Returns the type of the expression as a string. You can use this string to create another object of the same type, compare the type of two different objects, ensure that an object is of a specific type, etc. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void <expr> void |
17 | Transforms the result of expression to void (that is undefined). This is similar to a cast. I am not too sure why we need this cast since you could put undefined in your expression as is if need be. Note: SSWF tries to optimize many things and this one is one of them. When SSWF finds a void, it first checks to see whether the expression has a side effect, if not, then the whole expression is simply replaced by undefined. This can be wrong if one of the parameters in the expression is a getter or some operators used have some hidden side effects. To fix this problem: do not use void | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ <name1>: <expr1>, <name2>: <expr2>, ... <namen>: <exprn> } object declaration |
17 | Declares the list of members for a new object with the
members separated by commas (,). Each member is defined as a
name and a value separated by a colon (:). The name can be any
dynamic expression resulting either in a string or a number.
Putting a direct name as an identifier is view
as a static name unless you put that identifier between
parenthesis.var array = { a: 1, b: 2 };Create an object with two members: a and b set to 1 and 2 respectively. var array = { (a): 1, (b): 2 };In this case, a and b are viewed as variables and they need to be defined. Say a is set to first and b to second, then the new object will have two members: first and second set to 1 and 2 respectively as in: array.first = 1; array.second = 2; |
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[<expr1>, <expr2>, ... <exprn>] array declaration |
17 | Creates an array from the list of items specified between square brackets and separated by commas. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
function ... function |
17 | Declares a function as a literal. The main purpose of
this syntax is to create dynamic functions that you can attach
to an object as a function member. Functions can also be
saved in variables and later called with a syntax such as
(func)(...).
|
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ** <expr> power |
16 right |
Returns the first expression to the power of the second expression. Note that this operator has a right priority. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> * <expr> multiply |
15 | Returns the multiplication of both expressions. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> / <expr> divide |
15 | Returns the division of the first expression by the second. When both expressions are integers, then integer arthimetic is used. Otherwise it will compute a floating point value. If the second expression is zero, the expression will throw an exception. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> % <expr> modulo |
15 | Returns the modulo of the first expression by the second. When both expressions are integers, then integer arthimetic is used. Otherwise it will compute a floating point value. If the second expression is zero, the expression will throw an exception. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> + <expr> add |
14 | Returns the addition of both expressions. When both expressions are strings, the result is the concatenation of both strings. Otherwise the operator, like the other arithmetic operators, will try to convert both expressions to a number. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> - <expr> subtract |
14 | Returns the first expression minus the second. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> << <expr> shift left |
13 | Shifts the first expression on the left a number of bits as specified in the second expression. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> >> <expr> shift right |
13 | Shifts the first expression on the right arithmetically a number of bits as specified in the second expression. This means the sign is being copied and thus negative values remain negative. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> >>> <expr> unsigned shift right |
13 | Shifts the first expression on the right logically a number of bits as specified in the second expression. This means the sign is ignored and zeroes are pushed in as the shift is applied. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> !> <expr> rotate right |
13 | Rotates the first expression on the right a number of bits as specified in the second expression. | 1.7.3 (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> !< <expr> rotate left |
13 | Rotates the first expression on the left a number of bits as specified in the second expression. | 1.7.3 (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> < <expr> less |
12 | Evaluates both expressions and compare them together. If the first expression is less than the second, the operator returns true, otherwise it returns false. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> > <expr> greater |
12 | Evaluates both expressions and compare them together. If the first expression is greater than the second, the operator returns true, otherwise it returns false. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> <= <expr> less or equal |
12 | Evaluates both expressions and compare them together. If the first expression is less or equal to the second, the operator returns true, otherwise it returns false. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> >= <expr> greater or equal |
12 | Evaluates both expressions and compare them together. If the first expression is greater or equal to the second, the operator returns true, otherwise it returns false. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> is <expr> is |
12 | Evaluates both expressions and determines whether the
object on the left is of the type defined on the right.
|
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> as <expr> as |
12 | Casts the left hand side expression to the right hand
side type. This expressions checks whether the expression defined
on the left is of the right hand side type or one of its supers.
If it is, then the left hand side object is returned. Otherwise,
this expression returns null. You can also write <expr>(<expr>) to cast the second expression (parameter) to some type (what looks like a function name.) |
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ~= <expr> match |
12 | Test whether the first expression matches the regular expression defined in the second expression. [an internal implemention is available since Flash 9 with ABC ActionScript, which I do not support yet. Note that won't prevent an overloaded operator from working, but of course, you have to write the matching function...] | n.a. (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> in <expr> in property |
12 | The first expression is evaluated and expected to be the
name of a property (also called member) to search in the
object defined in the second expression. If it is found,
this operator returns true, otherwise it returns false. WARNING: this syntax used in a for() has the effect of iterating through all the elements of the second expression, setting the variable defined as the first expression (which needs to be an identifier) |
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> in <expr> ... <expr> in range |
12 | Evaluates the first expression. Compare it against the second
expression. If it is smaller, return false. Otherwise, evaluate
the third expression. If it is larger, return false. Otherwise
return true. In other words, test that the first expression is
included between the bounds defined by the second and third
expressions. Note that if the second expression is larger than
the third, then this expression always returns false. Note that at this time both the range ( .. )
and rest (... ) operators are accepted
as the range operator. |
1.7.3 (*) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> instanceof <expr> object relationship |
12 | Defines the object type of the first expression and compare
to the name of the class defined on the right. If both are equal,
then return true. Note that equal means that the first expression
is exactly of the type specified or is a derived class of the
type specified in the second expression. For instance:
class A { ... } class B extends A { ... }; var b:B; b instanceof A === true |
1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> == <expr> equal |
11 | Compares the two expressions and determine whether they are equal. If so, return true, otherwise return false. All objects can be compared between each others to know whether they are equal or not. You can also compare void values such as null and undefined. The equal and not equal operators are loose in the sense that many objects will be equal to null and undefined. The strictly equal and strictly not equal operators, however, will compare objects exactly. Thus, two objects need to be of exactly the same class to have a chance to be equal. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> === <expr> strictly equal |
11 | Compares the two expressions and determines whether they are strictly equal. If so, return true, otherwise return false. Please, see the equal (==) operator for more information. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> != <expr> <expr> <> <expr> not equal |
11 | Compares the two expressions and determines whether they are different. If so, return true, otherwise return false. The <> operator is an extension and is available by default in SSWF. Macromedia supported that operator before and thus some people may still be used to it and since it does not break the syntax in anyway, it is still usable. Please, see the equal (==) operator for more information. | 1.7.3 (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> !== <expr> strictly not equal |
11 | Compares the two expressions and determines whether they are strictly different. If so, return true otherwise return false. Please, see the equal (==) operator for more information. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> & <expr> bitwise and |
10 | Evaluates both expressions, and applies a bitwise and (keep all the bits which are set in both expressions). | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ^ <expr> bitwise exclusive or |
9 | Evaluates both expressions, and applies a bitwise exclusive or (in the result, set all the bits which are not common to both expressions). | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> | <expr> bitwise or |
8 | Evaluates both expressions, and applies a bitwise or (keep all the bits which are set to 1 in both expressions). | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> && <expr> logical and |
7 | Evaluates both expressions, if both are true, returns true, otherwise returns false. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ^^ <expr> logical exclusive or |
6 | Evaluates both expressions, if both are equal, returns
false, otherwise returns true. This is partially an SSWF extension in the sense that it is not available in all Javascript implementations. However, because it is in the documentation of ECMAScript version 4, this implementation does not view this operator as an extension. |
1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> || <expr> logical or |
5 | Evaluates both expressions, if both are false, returns false, otherwise returns true. | 1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ?< <expr> minimum |
4 | Evaluates both expressions and returns only the smallest one, the other is lost. Note that this operator is different from the Math.min() function since it works on numbers, strings, boolean and any other object which can be sorted (i.e. which has one of the minimum (?<) or less (<) operators overridden. But the use of the less operator is not yet implemented in 1.7.3) | 1.7.3 (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ?> <expr> maximum |
4 | Evaluates both expressions and returns only the largest one, the other is lost. Note that this operator is different from the Math.max() function since it works on numbers, strings, booleans and any other object which can be sorted (i.e. which has one of the maximum (?>) or less (<) operators overridden. But the use of the less operator is not yet implemented in 1.7.3) | 1.7.3 (*) overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> ? <expr> : <expr> conditional |
3 | Evaluates the first expression: (1) if true, evaluates the second expression and returns it, (2) if false, evaluates the third expression and returns it. Note that only one of the second or third expressions will be evaluated. This means if you have a function call in one of them, that function will be called only when that expression is required. The second and third expressions can usually be assignment expressions. However, in some cases they are limited to conditional expressions. | 1.7.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr> <assignment> <expr> assignment |
2 right |
Assigns the expression on the right to the variable
defined on the left. The available assignment operators are
as described in the table below. Note that all assignments have the same priority. The right most assignment is applied first. Note that implies that the expression on the right be evaluated first which is exactly what SSWF does. The expression on the left does not need to be an identifier, it can be a dynamically defined variable name (i.e. a string) in which case you want to mark the corresponding variables with the dynamic attribute.
|
1.7.3 overload |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<expr>, <expr> list |
1 | Groups expressions one after another. The result is the
last element of the list. When used as a list of parameters, then each parameter is evaluated and each result is used for the corresponding function parameter. In that case, you can use a label to name the parameter that you are defining. Also, in a function that has a rest paramater (...) you can use ... to add all the arguments passed to your current function on to the next function. |
1.7.3 |
Void | The parameter list is empty. Whenever you call this function you cannot specify any parameters. No other parameter can be specified with Void. | 1.7.3 |
unprototyped | A strange idea indeed... Defines the prototype as being whatever. It is also said to be unchecked. This means you can call this function with really anything you want. No other parameter can be specified with unprototyped. This, in effect, also prevents the function from being overloaded. | 1.7.3 |
... | Needs to be defined at the end of your function prototype. It tells the compiler that any parameter, which isn't explicitly defined, will actually be passed in an array of arguments. The rest can be given a name to be referenced in your function (so you can access the different parameters and pass them down to other functions), but no attribute and no default value. | 1.7.3 |
const | Mark the given parameter as constant. You cannot modify its value in the function. (This is usually not useful but it can prevent some bugs from happening.) | 1.7.3 |
in | This parameter is an input parameter. This means that the function expects the caller to define this parameter. This does not mean the parameter will be defined. Parameters can be in and out at the same time. This is the default for all the parameters. | 1.7.3 |
var | This really is noise. All parameters are variables. | 1.7.3 |
out | This parameter is an output parameter. This means the caller can expects the function to define this parameter thought there isn't really any garantee it will happen. Parameters can be in and out at the same time. The use of this attribute forces the compiler to use an array to pass all the parameters to this function. This is (very certainly) not compatible with other compilers. It was done that way because Flash does not support this attribute. | 1.7.3 |
named | This is noise. All the parameters have a name (don't they?!) and thus a function can always be called with labelled expressions. This allows the caller to specify the parameters to a function in whatever order it needs (see below.) This is very important if some function calls have side effects. | 1.7.3 |
unchecked | The type of this parameter needs not be checked. In other words, it is considered to be Object. | 1.7.3 |
The function itself can have the following attributes:
true | The function will be included. | 1.7.3 |
false | The function will be ignored. | 1.7.3 |
intrinsic | The function is defined internally to the system (Flash in our case). In gereral, this means the function will be really fast and you will not find a Javascript body. | 1.7.3 |
constructor | The function is an alternative constructor. This attribute implies that the function is static. | 1.7.3 |
unused | The function cannot be used. If that happens, an error
occurs. When the function is not marked as dynamic, it will not
be assembled and thus only the compiler may generate errors. However,
whenever it is marked dynamic, such a function may be called at
run time. Because of that, the SSWF assembler generates a
function with this statement:throw Error("A function marked 'unused' cannot be called.") This is practical to debug a program in which some functions are being retired. |
1.7.3 |
public | The function is publicly available. Anyone can call it from anywhere. This is the default. Note that sub-functions are only visible in the scope in which they are defined whether they are marked public or not. | 1.7.3 |
private | The function is private and can only be called from other functions in the same class functions or package. | 1.7.3 |
protected | The function is protected and can be called from functions in the same class and derived classes. | 1.7.3 |
internal | The function is internal to a package, it can be called by all the functions of the same package or sub-packages only. | 1.7.3 |
static | The function is static and can be called at any time (opposed to a function member that can only be called when you also specify an object instance.) | 1.7.3 |
abstract | The function is abstract and needs to be defined in a derived class (in a final Flash movie, it will be defined as an empty function.) An abstract function cannot have a body. | 1.7.3 |
virtual | The function is virtual and can be overloaded. Note that all functions are implicitly virtual. Though a function marked final cannot be overloaded, it still is a virtual function in ECMAScript. | 1.7.3 |
final | The function is final meaning it cannot be overloaded in a derived class. [Note: Flash does not enforce this rule and thus you can still dynamically add a function of the same name] [Our compiler could generate some extra code to enforce this attribute (i.e. create a function on every class to ask the class whether some other function can be dynamically declared) to be really 100% compliant! But is that really useful?!] | 1.7.3 |
array | The function calling convention is forced to using
an array. Note that if one or more parameters of your function
uses the out attribute, then this calling convention
is automatically selected. This can be slightly faster if you have many parameters because it will not have to first save the data in registers and then on the stack before calling the function. It puts everything in the array at once. [This is true only if you do not make use of default parameters that reference other parameters since in that case you need to have their values in registers anyway] [The current implementation does not follow these rules 100%] |
1.7.3 (*) |
The compiler will search for a function in the current scope, then go up in each scope it can find (backward and forward). Similarly, a function member is searched forward in a class starting at the beginning of the class.
Whenever a function matches, its prototype is checked against the list of parameters that the caller is giving that function. Note that can be a complex matter since the parameters can be given in any order and some parameters can receive default values. The compiler will always take the function that matches best the caller's list of parameters. For instance, a function with a rest will not be selected if another function without a rest matches the caller parameters. This is called overloading. If you want to avoid such selection, you will need to ensure that all your functions have a different name. Note that two functions with the same prototype (also called signature) in the same scope is an error.
As mentioned in the table above, functions can be called with a list of parameters that are named (or labelled.) The SSWF implementation is quite relax in that respect since it will accept a mix of named and unnamed parameters as long as the type of the unnamed parameters match the next unused parameters of the function being called. Note however, that the fact that a function has a rest, will not force the compiler to try to make use of it for parameters that do not match the next entry. You name a parameter in a call by putting its name (identifier) followed by a colon before the value. A rest parameter is always considered to have a lower priority than a prototyped parameter. This means if two functions match but more parameters are accepted on one of them without counting the rest, then that one function will be selected.
function test(a, b, c) ... ... a = test(c: 33, 57, b: "Hello");
In this example, the function test is called with
(57, "Hello", 33)
. The 'b:' could be
removed. Note how named and unnamed parameters can
be used in the same list.
IMPORTANT NOTE: | The ECMAScript version 4 does not allow for named parameters to be passed as described here. For this reason (I would think, or I missed it), the order in which the parameters are evaluated is not specified in the reference. On my end, it makes sense to evaluate them from left to right in the order the user specified them, just like in a list expression. In other words, in the previous example, it will compute the value for 'c' first, then 'a' and finally 'b'. |
A function can be given a type. There are two special types for a function: Void and Never. Use Void whenever a function does not return anything. In this case, you can call the function a procedure. In case of Flash, the caller will be the one throwing out the return value. The Never type is very special and it means that the function never returns. This cannot be used with Flash since no function can loop forever. However, it is available in the language. Trying to use a Never function with SSWF compiler generates an error.
Overloading operators is a feature available in the SSWF implementation. Functions used to overload an operator are supposed to define the operator in a String. SSWF accepts operators as is since it does not break the syntax at all. The operators that can be overloaded and what they do are all defined in the Operators chapter.
break
break [<label>];
The break statement is used to stop the current loop or switch statement and continue with the statements following that loop or switch.
The break statement can be followed by an identifier. This can be used to break all the loops up to the one named by that identifier. In effect, it is similar to using a goto statement with a label after the named loop or switch statement.
Note that the current implementation of SSWF does not allow you to break from within a try/catch/finally or with block to outside one of these blocks.
continue
continue [<label>];
The continue statement is used to stop the current loop try to repeat it. It will run the loop test and if true, restart the loop, if false, it stops.
The continue statement, when labelled, can also be used to continue a switch. This means the next case statements are checked and the first that is true is executed. In other words, multiple cases can be run within a single switch.
A continue with a for loop with counters goes to execute the next statements and then executes the test expression. As expected, if the test returns true, the loop repeats, otherwise it ends.
A continue with a for loop enumerating an object members sets the for variable to the next member and repeat the loop unless there was no more member names in which case the loop ends.
A continue with a do/while loop jumps to the while and runs the test. If the test returns true, then the loop is repeated. Otherwise the loop ends.
A continue with a while loop, jumps to the while and runs the test. If the test returns true, then the loop is repeated. Otherwise the loop ends.
A continue can be used to continue a switch statement. In this case, it has to be labelled. (This is because 99% of the programmers out there would otherwise be caught unaware of this special feature of SSWF since the default behavior is to continue the loop inside which the switch statement is found.) The label will be defined right before the switch statement to be continued.
The continue makes the flow control continue on to the following case statement. This would not be very useful if the cases only accepted constants and the switch statement only used the strictly equal operator. The fact is that SSWF enhanced the switch statement dramatically to where you can specify the operator to use to do comparisons with, the case expressions can be fully dynamic and also cases can specify a range. Because of that, it does make sense to have a way to continue testing the available cases. This can be achieved with the continue statement or the foreach attribute.
Note that the current implementation of SSWF does not allow you to break (continue with a label of an outer loop or switch) from within a try/catch/finally or with block to outside one of these blocks.
do
[<label>] do ... while(<expr>);
The do statement is used to create loops that are executed at least once. The loop ends with a while and a boolean expression. The loop repeats as long as the expression is true.
do { // executed at least once a++ my_func(a); } while(a < 10);
The do and while statements can be used to create blocks that can be broken at any time. This can be useful whenever you have many conditions that can break the current code, but you still need some sort of clean up to happen afterward.
do { if(a == b) { ... break; } if(c == d) { ... } if(e == f) { ... break; } ... } while(false); // do my clean up here ...
This example shows you how to use the break statement as a goto. This is usually preferable to a goto and label (and this is the only method available in all ECMAScript versions.) Note that the loop, in itself, is not really a loop since the while will never repeat the loop. This is just a block you can break.
If you want to create a loop that loops forever, you should
use for(;;)
instead.
for
(loop)[<label>] for(<expr>; <expr>; <expr>) ...
There are three ways to use the for statement. Here we explain
the for statement when used to create loops with counters.
This version can also be used to create loops that loop forever:
for(;;)
.
This for statement is expected to have three expressions: one for initialization, one for testing whether to execute the statements in the loop called the condition and one to update the counter variables called the next expression. Each expression is separated by a semi-colon. The initialization expression can include variable definitions. All expressions can be empty. When the condition expression is empty, the loop cannot stop unless you have a break or a goto within the loop.
for(<init>; <test>; <next>) ...
Most of the time, the initialization is something like var i :=
0
, the condition is something like i < max
and
the next expression looks something like ++i
. But of
course, the possibilities are endless. All the expressions are
supported in each of the three parts of the for. Note that
the next expression (3rd) will not be evaluated if the condition
expression returns false on the first try.
Note: SSWF does not prevent you from using the in operator in a for expression. The distinction between the two for's is very simple: one has two semi-colons and the other does not even have one. You can look at the source code if you are wondering how it works. It is actually pretty straight forward and it avoids us having to transform the behavior of the lexer whenever we parse a for loop.
SSWF supports having more than one variable definition in the initialization expression. So for instance, one can write the following:
for(var i := 5, j := 0, k := 8; i < max && j > min && k == 8; ++i, --j, k += magic) { ... }
For forward and backward compatibility, it is adviced that you do not use that feature. Also, the variable types cannot properly be defined inside the for.
for ... in
(enumeration)[<label>] for(<name> in <object>) ...
There are three ways to use the for statement. Here we explain the for statement when used to go through all the enumerable members of an object.
This for statement is used to loop over all the members of an object. The result is to get a string that represents the name of a member and repeat the process until all the members have been named. The object member can be read using the syntax: obj[name] or obj.(name). For arrays, the members are integers.
The following example makes the integral sum of all the members of an arbitrary object:
var total: Integer := 0; for(m in obj) { total += obj[m].toInteger(); // or: total += obj.(m).toInteger(); }
for each ... in
(value enumeration)[<label>] for each(<name> in <object>) ...
There are three ways to use the for statement. Here we explain the for statement when used to enumerate the values of all the enumerable members of an object.
This for statement is used to loop over the values of all the members of an object. The result is similar to the usual for ... in except that the variable is automatically set to the value of each property available in an object or an array.
The following example makes the integral sum of all the members of an arbitrary object:
var total: Integer := 0; for each(m in obj) { total += m; }
Note: if a method is marked enumerable in your object, then it will be listed too. You may want to test the type of the value before to use if that can happen.
goto
goto <label>;
The goto statement is used to jump to a user label. The control flow changes at once from the current position to the indicated label. The goto cannot be used to jump outside or inside a function, package or program (i.e. you cannot cross the boundaries of one of these definitions).
Thought SSWF will at some point accept to go to in and out the try/catch/finally and with blocks, at this time this is not implemented. You can still use the goto intruction within or past one of these blocks.
function test(var a: Integer := -1): String { if(a == -1) goto not_user_defined; with(Math) { ... } return "User"; not_user_defined: ... return "Internal"; }
Note that the implementation of the goto statement is an SSWF extension. It is not available in ECMAScript, only reserved.
if/else
if(<expr>) ... if(<expr>) ... else ...
The if and else statements are used to test a condition and execute code when it is true and optionally when it is false. The construction is as follow:
if(<expr>) { // execute when <expr> is true ... } else { // execute when <expr> is false ... }
The else and following block are optional.
At times, you need to use a condition to select between two values and then save the selected one in a variable. This can often be achieved with the use of the conditional expression instead, which can be faster.
// with a conditional if(<expr>) { // execute when <expr> is true my_var := <value 1>; } else { // execute when <expr> is false my_var := <value 2>; } // a faster way is to write this instead: my_var := <expr> ? <value 1> : <value 2>;
label
<label>:
The user can enter labels to use with the goto, break and continue statements.
In case of the goto statement, the control flow continues right after the label. If the goto is done from within loops, it first breaks these loops.
When used with a break statement, the control continues after the loop (for, do, while) or switch named on the break statement. Using the break with a label let's you break multiple loops at once.
When used with a continue statement, the control flow continues at a different place depending on the statement being continued. Note that when used with a label, the continue first breaks all the inner loops and switches up to the loop or switch having the specified label. Please, see the continue statement for more information about how the continue is handled.
return
return [<expr>];
The return statement is used to end a function right away and to return a value to the caller. Using the return statement outside a function is an error.
Note that in ECMAScript, all functions return a value but functions marked as returning Void will actually return the special value undefined. Flash will automatically add undefined on the stack if a function does not explicitly return anything.
The return statement needs to have an expression when the function does not return Void. And vice versa, the return statement must not return an expression when the function returns Void. The return statement cannot be used when the function returns Never since this special type means the function never returns.
Note that in effect, the return statement is very similar to a goto statement which makes sure that there is one value on the stack after it jumped to the end of the current function.
switch
[<label>] switch(<expr>) [with(<operator>)] [switch attribute] { case <expr>: ... default: ... }
The switch statement is used to test multiple values at once. This is very similar to a set of if/else statements used in a slightly more structured form.
The SSWF support of the switch statement has been enhanced to:
Also, but I do not think this is an extension according the ECMAScript reference, the expressions following the case statements do not need to be constants.
By default, a switch statement will:
WARNING: |
Because expressions in a case statement can by dynamic, this
means you can put in there expressions with side effects
(i.e. a++, increment(v), etc.).
For this reason, all the case statements, unless seen as
constants, will be evaluated in the order you gave them.
This is very important to know the final result, and
it can still be very complicated to know which case statements
will be selected! Yet, the switch expression can be a constant
integer, string, double, that is tested against multiple
dynamic expressions:
switch(9) { case varA: ... case varB * 2: ... case varC + 3: ... ... } |
The enhancements change the default behavior of the switch statement by allowing you to:
default | Strictly Equal or in |
This is the default. It accepts either one value cases tested with the strictly equal operator or ranges which are treated as specified with the 'in' operator used with a range. Use the default label if you want to specify the default. | 1.7.3 |
=== | Strictly Equal | This is kind of the default. However, if you specify this operator, the range feature will not be available. See the 'in' operator to know how to specify a range. | 1.7.3 |
!== | Strictly Not Equal | Accept all the cases which do not match the switch expression. | 1.7.3 |
== | Equal | This is similar to the default but it is loser in comparing values. For instance "" == null is true. | 1.7.3 |
!= | Not Equal | The opposite of the Equal operator. It will think that more values are equal and thus more tests will fail. | 1.7.3 |
instanceof | Instance Of | Compare two objects together and accept the case only if the switch statement is an instance of the object specified in the case expression. | 1.7.3 |
> | Greater | True if the switch expression is greater than the case value. | 1.7.3 |
>= | Greater or Equal | True if the switch expression is greater than or equal to the case value. | 1.7.3 |
< | Less | True if the switch expression is less than the case value. | 1.7.3 |
<= | Less or Equal | True if the switch expression is less than or equal to the case value. | 1.7.3 |
in | In | True if the switch expression is in the case range.
Note that the test is inclusive. In other words,
a range such as case 3 ... 7: matches
all the values greater or equal to 3 and less or
equal to 7. Note that when you are using this operator
you have to make all the cases use a range. |
1.7.3 |
~ | Match | Match a regular expression. | n.a. |
is | Is Instance Of | Test whether an object is an instance of a given type. | 1.7.3 |
as | Is Object of that Type |
True when the object specified in the switch statement is of the specified type. | 1.7.3 |
Note: | Statements other than definitions cannot be attributed like a definition or a simple block can. However, since a switch statement needs to have a block to encompass case and default statements, the attributes can be mentioned right before that block. |
The with keyword is used to specify the operator. At this time,
it is assumed that we want the parenthesis though SSWF does not
enforce their usage (switch(my_var) with > { ...}
is valid).
At this time it is fine since there cannot be any confusion.
Each case statement can be defined as a range. This is done by defining two values separated by a rest (...). The values specified are included in the range. So for instance, the range 3 ... 13 includes all the values from 3 (included) to 13 (included). Note that you need to put spaces before and after the range operator. This is because the lexer would otherwise see numbers as floating points.
The continue statement is explained in depth in its own section. In brief, from any statement of a case that matched, you can request the next case to be checked instead or breaking or falling through.
throw
throw <expr>;
The throw statement is used to raise an exception.
By throwing, you generate an exception. The expression after the throw statement will be used as the exception expression. To catch an exception, you need to run your code in a try block and have a corresponding catch block. The expression on a throw statement can have any type. The catch statement can specify a specific type so the handling of the exception can be made specific to a type of object.
try/catch/finally
try { ... } catch( <param1> : <type1> ) { ... } catch( <param2> : <type2> ) { ... } ... catch( <paramn> : <typen> ) { ... } catch( <paramno-type> ) { ... } catch(...) { ... } finally { ... }
The try, catch and finally statements are used to handle exceptions. The try statement is followed by a block of statements which are executed safely meaning that they can generate an exception and the process will not just stop. Instead it will continue in a catch statement block (if there is one available). In all cases, the (clean up) statements in the finally block will be executed (when one was defined).
The try statement and block of statements has nothing specific to it. It needs to be followed by at least a catch or a finally statement. A try without any catch will only ensure that the finally statements are executed, but the exception will be thrown again as soon as the finally block exits.
Several catch statements can be specified to catch different type of exceptions. The type of an exception is determined using the type of the expression given to the throw instruction. The type of the exception expression has to match the type of the catch parameter for that specific catch statements to be executed. There is no restriction on the type a throw and catch can use to generate exceptions in SSWF, but it looks like the Flash player only accepts Error objects and objects derived from the Error object (TBD -- if it is the case the compiler should err about it!).
WARNING: |
SSWF disagree somewhat with the numerical types. With Flash
all numbers are defined as Number . Make sure you do
not use Integer or Double as the type
even though many times your variable will be of that specific
type it will not be recognized as such at run time! And... why
would you want to use such a type for an exception?!
|
The order of the catch statements can be important depending on whether a type is derived from another. You may have to pay attention to that. Also, only the very last catch can be untyped or use the rest (...) operator. Such a catch will match any exception. When you do not need to check the exception expression, you can use the rest (...) operator. This ensures you do not reference the parameter if you did not want to.
When there is one or more catch statements, all have a typed parameter, and none of these types match the exception thrown, the exception is raised again. Note that the finally statements will still be executed. This is similar to the following code:
catch(exception) { throw exception; }
It is possible to not have any catch handlers. In this case, you need to have a finally statement. Note that exceptions are caught until the finally executes, but then they are thrown again once the finally exits. If an exception happens while executing the finally block of statements, then the old exception is lost and the new one is propagated.
The finally statement must be the last if it is to be used. It defines a set of statements to be executed in order to exit the try statement cleanly. In general it will ensure that some temporary objects were properly deleted. The following examples shows you how a user object is first newed in the try statement and then deleted in the finally.
var o: MyObject; try { o := new MyObject(p1); o.Init(); // this can throw o.Execute(); } catch(e: MyError) { if(e.name == "Really Bad") { print("We're in trouble"); throw Again(33); } } finally { delete o; }
Note that in such a script, the variable o would at some point be set to undefined and if there is no other reference to the object o, it would anyway be deleted. The explicit delete ensures that even if there is another reference somewhere else, it will surely be deleted.
WARNING: | Flash 7.x has a bit of a hard time with the cast instruction. I will add some proper support to get the right type at a later time (by adding a special variable member such as __typeof to all user classes.) But this could have been fixed in v8.x. |
while
[<label>] while(<expr>) ...
The while statement is used to create loops. It is very similar to the do statement except that the test is run once before to execute any of the statements following the while.
Note that a while(false) ... statement is reduced to nothing. Thus, if your expression can be reduced to false at compile time (i.e. it is constant at compile time,) then the entire statement is ignored.
with
with(<expr>) ...
The with statement is used to avoid having to specify an object on every single statements. Any variable or function used inside the block of statement following a with will first be looked for in the specified object, then functions and variables defined outside the with block.
This can be particularly useful if you are to use many Math functions. The following show a small example:
function circle_surface(radius: Double) { with(Math) { return 2 * PI * pow(radius, 2); // In SSWF, the power can be written like this too: // return 2 * PI * radius ** 2; } }
Note that the SSWF implementation currently forbids you from using with with the this reference. There should be no reason for the end user to do so anyway.
Classes, interfaces and enumerations are supported in SSWF.
Enumerations are lists of names which can be assigned a value or are automatically assigned the previous value plus one.
enum <name> { <name1>, <name2>, <name3>, ... <namep> = <expr>, ... <namen> };
The name of an enumeration is optional. When specified you can use it as a type. Note that an enumeration cannot be used to create an instance later. It is only a declaration.
The first value (<name1>) is set to 0 when no value is specified.
A value can be specified using the usual assignment operator. Note that enumerations can use dynamic expressions (i.e. the expression does not need to be a constant). This is an extension of SSWF and it may be removed later. It is experimental.
A class defines an object that you can later instantiate using the new operator.
A class can be composed of function members, variable members and sub-classes. Also, it can inherit of one other class and any number of interfaces. It can have a constructor.
class extends <class name> implements <interface name1>, <interface name2> ... <interface namen> { // variables var <name> = <expr>; // constants const <name> = <expr>; // functions function <get|set> <name>(<parameter>, ...): <type> { ... }; // sub-classes class <name> { ... } }
Note that a class does not need to extend Object. That is the default.
A variable can be a constant. A function is considered a constant
(it cannot be overwritten, this is enforced at run time). All members
are considered invisible and not deletable by default. If you want to
make a member available to the
for(... in ...)
or
for each(... in ...)
enumerators (i.e. visible), then you need to mark it as enumerable
(this is a member attribute). To make members deletable, use the
dynamic member attribute.
The following table lists all the attributes which can be used with classes. Note that some attributes are expected to be defined on the class itself and others on the members in a class. Of course, since a class can be a sub-class of another class, it can be considered a member and thus all the flags are applicable to classes. Note that some attributes, such as dynamic and final are somewhat special. Note that interfaces cannot be dynamic and even less final.
abstract member |
This function member cannot have a body (also the class needs to be derived since we are not supposed to be able to create instances of this class.) | compile | 1.7.3 |
constructor member |
This function member is an alternate constructor. | compile | 1.7.3 |
dynamic1 class |
Objects of this class can have members added and removed at run time. Members can be deleted. | run | 1.7.3 |
enumerable member |
The member will be visible to the
for(... in ...) statement. |
run | 1.7.3 |
false all |
The class or member will be excluded (not even compiled). | compile | 1.7.3 |
final all |
The member cannot be overridden or shadowed. The class cannot be derived. | compile | 1.7.3 |
intrinsic member |
The member is defined in the system (i.e. Flash Player). This attribute can be defined anywhere. When defined on the class, then all the members are intrinsic. | compile | 1.7.3 |
private all |
The member can only be used by class member functions. | compile | 1.7.3 |
protected member |
The member can only be used by this and derived class member functions. | compile | 1.7.3 |
public member |
The member can be used by anyone. | compile | 1.7.3 |
static member |
The member function can be called or a variable can be accessed without creating an instance. | compile | 1.7.3 |
true all |
The class or member will be included. | compile | 1.7.3 |
unused function member |
This function is not expected to be used at any time. | compile | 1.7.3 |
virtual member |
This function is expected to be overridden in other classes. This is the default. | compile | 1.7.3 |
1 the following system objects are dynamic:
Other system classes cannot be dynamically altered. [for hackers: this is only a compiler test, you can either remove the test in the compiler (search for IsDynamicClass() and always return true) or add the dynamic keyword on the classes you want to extend. The Flash player doesn't enforce these rules at run time, at least not in version 7.] |
Note: | If you want to change the settings of a member of an object at
run time, use the ASSetPropFlags() function. This is
not documented by Macromedia, but it works perfectly in the Flash
player versions 5, 6 and 7. |
// The following is an undocumented function used to setup the // protections of the different properties of an object // OR these values for the flags; you may need to set 'allow' to true // to change a flag from 0 to 1 const var PROP_FLAG_CAN_OVERWRITE = 4; const var PROP_FLAG_CAN_DELETE = 2; const var PROP_FLAG_IS_HIDDEN = 1; // set props to the array of properties you wish to change protections // (or use null for all of them) function ASSetPropFlags(obj: Object, props: Array, flags: Integer, allow: Boolean = false);
To see everything and make it dynamic (overwritable and deletable),
use null
for the array, set the flags
(PROP_FLAG_CAN_OVERWRITE | PROP_FLAG_CAN_DELETE)
and set
allow to true
to force the new value.
ASSetPropFlags(MyObject.prototype, null, PROP_FLAG_CAN_OVERWRITE | PROP_FLAG_CAN_DELETE, true);
With this function at hand, you can list the entire system available to you in any Flash Player.
Defines an interface just like a class. The few differences are: interfaces cannot include a constructor, interfaces cannot extend anything, interfaces cannot include sub-classes.
The idea of an interface is to create variables of that type and have function prototype tested by the compiler. There is otherwise not much to interfaces. In ECMAScript, you do not otherwise need to have function prototypes, so it is not absolutly necessary to define interfaces.
SSWF accepts packages. These can be defined in the .sswf files or externally. SSWF will automatically load the system packages and make them available as they are supposed to be.
The internal packages define the Global objects available by default in ECMAScript, the System and Native Flash objects. These are the packages which are automatically loaded for you. You do not need to specify any import statement to access these objects (even though in SSWF, all of these are really defined in packages!)
SSWF also offers some extensions (such as Complex). Extensions are not part of the system and thus you need to explicitly import extension packages.
To use objects defined in one of your own packages, you also need to specify your package in an import instruction.
For SSWF to find an external package, you first need to compile the package with asc. This will ask the compiler to record the objects (classes, interfaces, variables, etc.) defined in the package in the packages database. Once in the database, the import will be able to find the package again in order to instantiate it in output files. Note that the name of the package has nothing to do with where to find the package on your file system.
The database of all the package objects is saved in a text file that you can look at. It is strongly suggested that you do not modify the file. You can, however, delete it if you delete one of your package. This will prevent SSWF and asc to try to look for that package later. If you delete your database, you will need to recompile all of the packages you still want to use with SSWF using asc.
The database file is named in your setup file. It needs to be in a directory where you can create a file and then read and write in that file.
When you create a Flash movie, the packages are not automatically implemented in the movie. You need to specifically tell the compiler to include a package in the output movie using a pragma and the import instruction.
use pragma instantiate(true); import my_package; use pragma instantiate(false);
Packages can include classes, interfaces, variables and functions. You can make the definitions internal, in which case only the package sees these definitions. You can make a definition private. Then only functions in this specific file can access the definition.
A package can include another package. You can access sub-packages as you access sub-classes, with the use of the member operator.
SSWF supports a certain number of pragmas as defined in the table below. The system conforms to the ECMAScript reference. Most pragmas supported by SSWF are specific to SSWF.
The syntax of pragma is a list of identifiers optionally followed by one parameter and a question mark. The question mark can be used to test whether some option is turned on or off.
use pragma <name> [ '(' <value> ')' ] [ '?' ] ... ;
The parenthesis are optional if you do not define a value. By default the value is 0 or 1 (i.e. 0 when negative and 1 when positive).
For instance, you can turn on the use of extended operators with
use pragma extended_operators;
or use pragma extended_operators(1);
. In a package, you
can test to make sure that extended operators are available (if
you make use of them, that's a good idea to do so) with use pragma
extended_operator?;
.
You can specify multiple pragma's one after another on the same line as in:
use pragma extended_operators octal strict;
Because of the pragma question feature, most pragmas will have an opposite defined. For instance, the extended_operator has the opposite no_extended_operator.
Note: in the table below, the default presents what SSWF sets as the default options. It is not automatically the default of the asc (library) compiler.
use pragma [no_]extended_operators(boolean); | true | Whether you want extended operators to be supported. SSWF automatically turns this pragma on. You can turn it off to make sure that you are not using any extended operator. The extended operators are defined in the table of operators. For instance the power (**) operator is an extension. | 1.7.3 |
use pragma [no_]extended_escape_sequences(boolean); | true | Whether you want extended escape sequences to be supported. SSWF automatically turns this pragma on. You can turn it off to make sure that you are not using any extended escape sequences (such as \e). | 1.7.3 |
use pragma [no_]octal(boolean); | false | Whether you want octal number to be accepted. ECMAScript version 4 is fading out octal support and thus by default this is not available. | 1.7.3 |
use pragma [not_]strict(boolean); | always true | Whether you want all your statements to end with a semi-colon. SSWF does not currently make use of this flag. It is mostly strict all the way. At this time, the only escape is a closing curvly bracket. In other words, you can omit the semi-color just before a closing curvly bracket. Though it isn't recommended to use that feature since adding a new line will break the code. | 1.7.3 |
use pragma [no_]trace(boolean); | false | By default, SSWF considers that you do not
want to trace anything and thus it turns off the
trace feature. If you want to add support for the
trace feature, you need to specify this pragma:
use pragma trace(true); To use the trace function, you also need to import the Extensions since trace() is one of the extensions.
|
1.7.4 |
use pragma [no_]trace_to_object(boolean); | false | By default, SSWF supposes that you want
the trace() function to stay the same as it is.
The SSWF assembler, however, supports a special
feature which can be used to transform the trace()
call in a method code on the Trace object. So
the following call:
trace("My Debug", "More Info");is changed to Trace.Message("My Debug", __NAME__, __FILE__, __LINE__, "More Info");This enables us to have a much better debug feature since in this way you know exactly who is generating the trace, from which file at which line and you also can have as many parameters as you want (the first is passed first to the Message() function and the
others are passed last via the rest (... ) feature.)I offer a default Trace.Message() function, but you
are very welcome to write your own.
|
1.7.4 |
At this time, SSWF does not support name spaces. The lexer will read them and the parser will accept most of them, but the compiler and assembler will not know how to deal with them. So do not use them.
In this chapter I will try to answer some questions before they are even asked and put what I think has value in understanding the internals of the SSWF ActionScript compiler. There are problems with this compiler just like with any compiler and I am trying here to explain why I chose to do thing one way rather than another. I also mention quirks in the grammar, lexical or Flash which we cannot really go around, or for which there isn't a clear answer.
Like most compilers, SSWF will generate temporary variables and for those it will need to use auto-generated names and registers as it sees fit. Within a function (V7+ of Flash) we have up to 254 registers available. SSWF will make use of as many as possible to avoid using variables. Registers are a lot faster to access since these are accessed by number instead of name like variables.
Registers, you don't really need to know whether they are used or not. These won't clash with anything you are doing. However, when not in a function, or in a really large function using lots of variables, you can still find yourself out of registers. At that point, the compiler will generate a name. At this time, all names will start with two underscores, a letter and a unique number (the number will be unique in the entire SWF file.) The letter will change depending on the use of the variable (see table below.) This can be important since you should NOT name one of your variables with any of these names. I don't forsee too many people using names of dynamic variables starting with two underscores anyway... right?
__g<number> | Global variables use the 'g' letter. Globals are variables defined outside a function or class. SSWF automatically rename your variables unless you mark them as being dynamic (see talk about dynamic variables below). This is because if you need to share variables between different programs in SSWF, you should define them in _root or _global and not try to use global variables. |
__l<number> | Local variables use the 'l' letter. Locals are variables
defined inside a function. Just like with global variables, SSWF
renames all of your local variables in this way. In general,
however, it will save your variable in a register. If you are
wondering why SSWF renames your variable, that's because otherwise
it is much harder to ensure distinct variables between frames.
For instance, one can write this:function test(a: Double := 3) { var b: Double := a ** 2; if(b >= 100) { var b: Double := sqrt(a); if(b <= 10) { var b: Double := a; return b; } } return b; }In this example, the variable 'b' is defined three times (which according to some references isn't legal, but it is allowed in SSWF.) In the case where the function returns prematurly (the inner most if()), it is fine since 'b' will hold the correct value. However, the last return needs to return a ** 2 and not sqrt(a). If SSWF wasn't renaming your variables, you would get the wrong result (note that if you try to compile this example, all the variables will be put in registers, but still, it will use three distinct registers.) |
__c<number> | Catch parameters use the 'c' letter. In general, just like local variables, catch() parameters will make use of registers if possible. Note that if you have several catch() one after another, they all will share the same variable. This is because once assembled, the resulting try/catch/finally block includes only one set of instructions for all the catch() entries in your code. |
__t<number> | Temporary variables use the 't' letter. Temporaries are used in expressions. These, you don't have a counterpart in your code. It is just often necessary to have a temporary variable to compute your expressions. Note: actually, if you look at it closely, there is really only three or four expressions which require the use of temporaries. The worst one is the function call, depending on your parameters, it can require one temporary per parameter. |
__f<number> | Local functions get renamed. These have the same
problem as the local variables. If you define two functions
with the same name in two different frames, it would be
viewed as one by Flash. This means you can use the default
function name to call a function dynamically. To fix that
problem, put your functions in variables and use variables
instead.
f1 = function (a) { ...} f2 = function (a) { ... } func = test ? f1 : f2; ... (func)(value); ... |
dynamic var <name>;
& undefined (or global variables)Example:
if(a < b) { var c: Integer; // place of interest if(b & 1) c := Math.sqrt(a + b); magic(c); }
In this example, c is set only if b is odd. By default, ECMAScript says that
a block of directive is a frame. Each time you enter a frame, you copy the
current frame to create a sub-frame and start working in that frame. This
means the variable c is created at that time. Because there isn't
any initialization, the value of c is set to undefined
.
In Flash, that doesn't happen because Flash has no notion of frames.
This means entering this if() statement when b is even, you could find
yourself with c already set from the last time you entered that if()
statement with an odd value in b.
To circumvent this problem, the SSWF compiler generates some extra code
to set local variables to undefined
whenever a frame is
being exited. In other words, you get the following:
if(a < b) { var c: Integer; // place of interest if(b & 1) c := Math.sqrt(a + b); magic(c); // auto-generated line: c := undefined; }
This ensures that you cannot reuse c with the wrong value anywhere in the code.
The problem now is that some variables that you want to define are
globals. These variables will receive the same treatment by default
and thus they would get deleted!!! But you mark them as dynamic
variables and the compiler will not generate that extra line of code.
Another way to avoid the problem is to use a variable member in the _root
or _global objects as in:
_root.a = 55; _global.b = 77.3;
Using the _root and _global objects is certainly the best way to go because these will always be available to you. The global is viewed by all the scripts and is the same object. There is one root per SWF file however. This is important only if you load movies in one of the 10 levels. Each level has its own root object.
WARNING: | As a remainder, dynamic variables do not respect frame boundaries. In other words, if you define two distinct dynamic variables with the same name in two distinct frames, it will be the same variable. |
But tell us... why did you invent dynamic variables if these are so bad and you are asking us to not make use of them?!
In Flash (in Javascript in general,) you can call certain functions
to create objects. These functions can accept a string as one of their
parameters. The string can then be used as the name of the variable
where that object will be saved. The MovieClip.createTextField()
is such a function. The first parameter is the name of the new movie
clip (i.e. a Sprite.) The following is an example of what you could
write in SSWF to create a similar function:
function createCar(var name: String, var weight: Float) : Void { var car := new Car(weight); // ... do some initialization (name) := car; // yes! 'return car;' would make more sense to me too... } ... dynamic var myCar; createCar("myCar", 1299.3); myCar.Run(); ...
So, more or less, the name of the variable in which the car object is to be saved needs to use a dynamic variable outside of this function. I don't think it is a good practice, but since Flash is using such an approach, I need to support it in SSWF.
In version 1.7.4, I'm adding support for the trace() function that creates a sprite and a text field in it with your trace message and some additional information automatically generated by the compiler and assembler.
To use this feature, you need to turn on the trace pragma:
use pragma trace(true);
If you want to make use of the advance trace() feature, then you need to use the trace_to_object pragma. This way the assembler will convert a straight trace() into a call to the method named Message in an class named Trace. The pragma goes like this:
use pragma trace_to_object(true);
By default, the compiler and assembler will turn off the trace feature and no code is generated for any call to trace().
The call to trace() is changed to a call to the Trace class like this:
trace("Hello!"); // becomes Trace.Message("Hello!", "<qualified name>", __FILE__, __LINE__);
The fully qualified name includes all the names from where the trace() is found up to the package in which it is included going throught functions, classes, interfaces...
If you look at the output code, you will eventually notice that declarations are assembled before statements. This is because Flash requires that a declaration be known before it can use it. For instance, it needs to have a function declared before it can call that function. For this reason, the assembler will first assemble functions, classes, interfaces and some other declarations and then it will compile the other directives, in general that will be statements including expressions.
This shouldn't cause any problem, however, it may look weird when you look at a switch statement since all of the declarations will be done before any case is being tested.
At this time, the SSWF compiler compiles these two operators as being the same operator. The is will behave exactly like the instanceof. I'm not too sure, but it certainly is correct simply because it is likely that the instanceof does not support comparison between function prototypes. Let me know if you find a problem with the is operator.
It is possible to declare sub-classes, however, at this time SSWF does not compile sub-classes properly. This is my next task with some other class related enhancements and bug fixes. So for now avoid any sub-class definitions.
On the other hand, SSWF accepts class definitions anywhere just as it ought to be. You gonna love that!
The parser is done properly and it will give you a good error feedback. At this time, the compiler and assemblers are not so good and they just print something like ERROR: message without any filename or line number. I will fix that very soon. I need to create an object to take care of writing messages on screen.
From within SSWF, the line numbers do not seem to start at the right value. I am not too sure whether SSWF has the wrong value to start the ActionScript parser or whether the parser itself is wrong. That too will be fixed soon. It should be easy enough.
In this version, user packages are not supported (that is, they will not be assembled). You can only use intrinsic definitions. This is on my TODO list along with the different class assembly which are still missing.
Overloading is declaring two functions with the same name but different parameters. This is supported by SSWF for common functions (those which are not defined in classes). At this time, classes do not support overloading.
There is one good thing about overloading, it make it easy to name functions! Then the system can just select which one to use. You have two ways to implement an overloaded function: (a) you create several functions with different parameters and (b) you create one function which accepts all kinds of parameters and checks its inputs at run time.
The second way (b) is always available to you in pretty much all languages as long as you can test the type of your parameters. The first way (a) is only available if your compiler and execution environment supports it. The Flash execution environment does not support overloading since it has poor data type support (at least up to version 7.x).
To circumvent the lack of overloading of Flash, SSWF will rename functions automatically and just call the proper function. You have nothing to do. You can prevent this renaming with the use of the dynamic attribute.
At this time, SSWF is not doing any function or variable member renaming. Thus, in a class definition SSWF does not support overloading (thought at this time it does not report problems.) This is because to support fully dynamic objects, the compiler cannot just rename members of a class. This problem may be fixed in version 8.x, but at some point, I will make the overloading work with version 7.x anyway. You will have to specify dynamic on members of a class that you want to call dynamically (i.e. with a name defined in a variable not known at compile time).
Warning: | typeof in version 5, 6 and 7 is limited to the internal
types; whenever you create your own class, it returns "object";
nothing more; I will program something to circumvent this limitation
though... |
Note that SSWF defines a type 'Integer' and a type 'Double' whereas Flash only has a type 'number'. This means you can't distinguish between an integer and a double in Flash. This includes the catch() statements. If you use a typed parameter named Integer or Double, the assembler will warn you and use 'number' instead. If you try to catch both types and/or number, then the assembler generates an error since you cannot catch the same type more than once.
Be careful whenever you test types. One way is to do something like this:
typeof <var> === typeof 0
At some point, SSWF may be able to transform a typeof
of a constant expression directly into its type. However, that
would cause the previous statement to break since 0 would
be viewed as Integer and typeof <var>
would return
Number.
Finally, note that the type returned by typeof in Flash is
given in lowercase (number, string, undefined, null,
movieclip, etc.).
Flash up to version 8.x uses empty Sprites to create object models (i.e. classes). This means you can only declare a class in the top level of your SWF movie. SSWF doesn't pre-parse all the objects to know whether some sub-'do action' tags include a class definition. Thus, it is currently your responsilibity to define classes and interfaces in do action scripts outside of sprites.
Since Flash 9, there is a new tag to support ABC scripts. These are not currently supported by SSWF. However, it will break the scheme of having to extend an object to create a class. This most certainly fixes the problems with the typeof keyword.
Because SSWF define Number as Double, it diverts from what it is supposed to be. The problem here is that classes in ECMAScript can only derive from one other class. Thus Number cannot derive from Double and Integer at the same time.
Also, the Flash Player (at least up to version 8) does not know anything about Double and Integer, only Number.
I have looked in this problem and came to the conclusion that the only way was to ask the programmers to put spaces. You could find the following in a source file:
if(a in 5..2) ...
The range should have been written with spaces as in
5 .. 2
. At this time, the lexer will see this
expression as 5.
and .2
and
the parsing will fail with a syntax error.
The problem is fairly complicated when you add all the cases. You can have a decimal point by itself (5.), a decimal point followed by an exponent (5.e+3), a member operator (5.toString() [decimal] or 5..toString() [floating point]), a range operator (5..) or a rest operator (5...). One solution is to forbid a dangling decimal point (i.e. a decimal digit would be required after the decimal point). However, the ECMAScript definition includes that dangling decimal point case.
The lexer and parser understand and accept getters and setters. The name of a getter is transformed by prepending "->". This a getter function named "variable" will be compiled as "->variable" in Flash. Similarly, a setter function named "variable" is compiled as "<-variable".
This means you cannot access getter and setter functions dynamically. The reason for using the <, > and - characters is simple: no other functions can be named that way by the user. Also, since you are supposed to have both a getter and a setter with the exact same, they needed to be distinguishable.
Jan 27, 2008 |
|
Nov 11, 2005 |
|
Sep 3, 2005 |
|
This document was last modified on .