# Adding New ActionScript Class

In this document, the term 'ActionScript class' refers to the C++ class which is instantiated by Gnash when some ActionScript code instantiates a corresponding class. The C++ class stores instance data and implements the methods which are called on the object in the ActionScript code.

Adding a new ActionScript class is relatively simple, but the process is complicated by the fact that the interface has evolved over time and the current code base represents several different formats. This document describes the current interface. The Boolean class should be considered the authoritative example of a modern ActionScript class.

ActionScript classes contain a header file and a C++ implementation. The name is usually the name of the class as it is called in the ActionScript specifications; for instance Boolean.cpp for the Boolean class.

## Prototype

In ActionScript, a prototype is a base object which contains all the methods that an instantiated object will contain. In short, it contains every part of the class except for the portions dealing with the storage of instance data.

In Gnash, the prototype of an ActionScript object is implemented as an as_object. At startup, the methods and properties of the ActionScript class are attached to the as_object. The following example demonstrates how methods can be attached:

    	static void
    	attachBooleanInterface(as_object& o) {
    	  o.init_member("toString", new builtin_function(boolean_tostring));
    	  o.init_member("valueOf", new builtin_function(boolean_valueof));
    	}

Static properties can also be added to the ActionScript prototype (dynamic properties are addressed later). They are attached in a similar way:

    	o.init_member("myProperty", as_value("HelloWorld"));

Properties which have been added in this manner can be directly accessed in ActionScript code without a function call, as this piece of ActionScript code compiled by Ming's makeswf compiler demonstrates:

    	// Get the value of the myProperty property
    	if (node.myProperty == "HelloWorld") {
    	  trace("MATCHED");
    	}

## Declaration

A new class should derive from as_object, which is the base class of every ActionScript object in Gnash.

## Instantiation

When a new object is needed, instance data is added to the methods and properties inherited from the prototype.

The init method should be called in the constructor in Global.cpp, where all other ActionScript classes are similarly referenced. This method constructs a prototype, which is implemented as an as_object. In addition, the method registers the constructor to be used for future object creation, and attaches methods and properties to the prototype.

## Methods

Every method you implement and attach will receive an &fn_call; data structure as an argument when it is called.

### Accessing Arguments

The arguments stored in &fn_call; should be accessed using arg(). For instance, the first element can be popped with fn.arg(0).

The element popped off the stack is an as_value object.

### Returning a Value to ActionScript

The return value should be an as_value object. For example:

    	  return as_value('Goodbye, cruel world.');

### Additional &fn_call; Members

There are two other useful members of the &fn_call; structure, namely this_ptr and nargs. The former points to the class which is invoking this method, while the latter is a count of the number of arguments in the stack.

You may also see instances of the env pointer being used. This is being deprecated. Instances which could be replaced with arg() are already deprecated; other uses will be deprecated in the near future.

Beyond the arg() method, there is one method of note. dump_args() can be used in debugging to output the entire argument stack.

## Dynamic Properties

This section describes accessors to dynamic properties. Read-only properties are described in the prototype section.

Accessors should be written as a single get/set method. Previously this was done by overriding get_member() and set_member(), but this practice is deprecated.

The accessor is written so that it sets the property if it is called with an argument, and puts the property in the &fn_call; result pointer. For instance:

    	void
    	MyClass::myProperty_getset(const fn_call& fn) {
    	  boost::intrusive_ptr<MyClass> ptr = ensureType<MyClass>(fn.this_ptr);

    	  // setter
    	  if ( fn.nargs > 0 ) {
    	    bool h = fn.arg(0).to_bool();
    	    ptr->MyMethod(h);
    	    return;
    	   }

    	  // getter
    	  bool h = ptr->MyMethod();
    	  fn.result->set_bool(h);
    	}

It has not yet been decided whether properties should be set in the exported interface or attached to instances of the class. A property is attached in the following manner:

    	boost::intrusive_ptr<builtin_function> gettersetter;
    	gettersetter = new builtin_function(&MyClass::myProperty_getset, NULL);
    	o.init_property("myProperty", *gettersetter, *gettersetter);

&asvalue; &object;