Wednesday, October 17, 2007

Full eval() functionality in ActionScript 3

Like many before me, I have lamented the crippled functionality of the eval() function in ActionScript. In many languages, eval() accepts a string parameter, and returns the numeric result of the string evaluated as an expression. This has many uses, from simple infix expression parsing, to building and executing code on the fly depending on the values not known when coding/interpretation/compilation occurs.

Because a full version of eval() (analogous to existing JavaScript functionality) would be useful in rich internet applications, I offer the following simple workaround for ActionScript. The key lies in the ExternalInterface class in ActionScript 3, available in Flash (since version 8) and Flex 2 +. The code below has been tested and works in Flex 2.

Note that if your compiled .swf file is running in the Flash player, the ExternalInterface will not be available. But if you are running in a browser, the ExternalInterface class goes out to the container .html file, and can run JavaScript functions that you define explicitly in the containing .html file.

Assume that you have two TextInput fields in your application, called txExpression and txAnswer. txExpression contains the expression you wish to evaluate, and txAnswer will receive the evaluated answer. I further assume you know the details of setting up the interface in Flex or Flash.

The code below goes into the ActionScript/MXML file:


public function evaluate(str:String):void
{
if(ExternalInterface.available)
{
txAnswer.text = String(ExternalInterface.call("parseStr", txExpression.text));
}
else
{
txAnswer.text = "Function Unknown";
}
}

Obviously, the else clause above should do some error handling, but for the sake of brevity and
clarity, we omit that here. the important line is in the if clause. the call method of the ExternalInterface object calls a JavaScript function defined in the container .html file for the .swf, which ActionScript 3 refers to as the "External Interface." Any parameters to the function follow the function name (as a String). Since the parseStr function does not currently exist in the .html file, we must add it.

Open up the container .html file (which will have the same name as your .mxml file and your compiled .swf file), and add the following JavaScript code to it:

<script language="JavaScript">
function parseStr(str)
{
var ans = eval(str);
return(ans);
}
</script>

Here's what's going on. The ActionScript function calls the parseStr function defined in the
containing .html file, passing the text attribute of txExpression to it. parseStr uses eval()
to evaluate the string, and returns the numeric representation of the evaluated string. This
returned value is then converted back into a String, and the txAnswer.text attribute is set
using this value.

I hope this solution helps you; it has certainly helped me. I wouldn't relish the idea of writing a
fully functional infix expression parser in ActionScript.

More to come later...

No comments: