⬆️ ⬇️

MXML compiler. Part 2. Non-string parameter initializers

Hi, Habr!



In the previous article, I spent some kind of educational program on the insides of the Flex-compiler (in terms of MXML) and told how to save myself from the problems of working with classes in MXML that require constructor parameters. Now we will analyze the other side of the question - setting the parameters to custom values ​​(for example, constants) without using the Binding mechanism (although it is very similar to it).





opening speech

I want to apologize in advance for the fact that this article came out later than I said - literally the very next day after the article I was hired, and there was simply no time :) Now everything was resolved, and I am ready to continue the cycle of articles.

')

I think everyone who somehow worked with Flex has come across something like this:

<TextField xmlns="flash.text.*" autoSize="{TextFieldAutoSize.CENTER}" /> 


If you look at the code that generates mxmlc, then it will look something like this:

 private function _MyOwnFlexFrameworkTest_TextField1_i() : flash.text.TextField { var temp : flash.text.TextField = new flash.text.TextField(); _MyOwnFlexFrameworkTest_TextField1 = temp; mx.binding.BindingManager.executeBindings(this, "_MyOwnFlexFrameworkTest_TextField1", _MyOwnFlexFrameworkTest_TextField1); return temp; } // binding mgmt private function _MyOwnFlexFrameworkTest_bindingsSetup():Array { var result:Array = []; result[0] = new mx.binding.Binding(this, function():String { var result:* = (TextFieldAutoSize.CENTER); return (result == undefined ? null : String(result)); }, null, "_MyOwnFlexFrameworkTest_TextField1.autoSize" ); return result; } 


Isn't there a bit too much code for such a trivial task of specifying a constant property, which by definition does not change?



Let's do it!



Our goal is to make a backward compatible version that would support autocomplete in the civil IDE, plus it would be visually familiar to Flex programmers. Considering all the listed requirements, I decided that the solution would look like this:

 <TextField xmlns="flash.text.*" autoSize="${TextFieldAutoSize.CENTER}" /> 


The idea to use the dollar symbol came from the ANT scripts, conveniently and clearly, as well as already familiar to a good half of the flashers.



I admit honestly, I started the process by searching all classes in the java.flex2.compiler.mxml.lang package (why in it? See the first article from the cycle;)) for the entry of the string "@ {", since it is from it that the so-called two-way bindings begin, and our implementation could build on it. And I was lucky! Immediately the parseBindingExpression method was found in java.flex2.compiler.mxml.lang.TextParser .



To designate the Binding expression, objects of the BindingExpression type are used , therefore, by analogy, we will create next to it (in the flex2.compiler.mxml.rep package) the ExactValueExpression class:

 package flex2.compiler.mxml.rep; public class ExactValueExpression { /** The source expression for this value */ private String exactValue; public ExactValueExpression(String exactValueExpression) { this.exactValue = exactValueExpression; } public String getValueExpression() { return exactValue; } } 


We will use it in our own class method java.flex2.compiler.mxml.lang.TextParser , which I decided to call parseExactValueExpression:

 /** * @param s the string to be parsed * @return ExactValueExpression or null */ protected ExactValueExpression parseExactValueExpression(String s) { int dollarIdx; int openBraceIdx = -1; dollarIdx = StringUtils.findNextUnescaped('$', 0, s); if (dollarIdx == -1) { // String doesn't start with "$" return null; } openBraceIdx = StringUtils.findNextUnescaped('{', dollarIdx + 1, s); if (openBraceIdx != dollarIdx + 1) { // open bracet not in place return null; } int closeBraceIdx = StringUtils.findClosingToken('{', '}', s, openBraceIdx); if (closeBraceIdx == -1) { return null; } String contents = s.substring(openBraceIdx + 1, closeBraceIdx); if (contents.length() == 0) { // Convert ${} to null contents = "null"; } //Don't include the braces (or parens since they will just get stripped). return new ExactValueExpression( contents ); } 


Which will be called BEFORE calling parseBindingExpression:

 protected Object parse(String text, Type type, Type arrayElementType, int flags) { if (!inCDATA(flags)) { ExactValueExpression exactValueExpression = parseExactValueExpression(text); if(exactValueExpression != null) { return exactValueExpression; } // binding? if (!ignoreBinding(flags)) { BindingExpression result = parseBindingExpression(text); if (result != null) { return result; } else { text = cleanupBindingEscapes(text); } } 




Now our construction is correctly parsed, it remains only to process it. We go to the java.flex2.compiler.mxml.rep.init.ValueInitializer method formatExpr already familiar to us from the previous article. Add 3 lines to it:

 if(value instanceof ExactValueExpression) { return ((ExactValueExpression) value).getValueExpression(); } 


We compile the project with the ant compiler command , waiting for the BUILD SUCCESSFUL (if you have not received such a result, check all the steps from the beginning).



Result



Let's change our original example by adding a dollar symbol:

 <TextField xmlns="flash.text.*" autoSize="${TextFieldAutoSize.CENTER}" /> 


If you did everything correctly, the result would be something like this:

 private function _MyOwnFlexFrameworkTest_TextField1_i() : flash.text.TextField { var temp : flash.text.TextField = new flash.text.TextField(); temp.autoSize = TextFieldAutoSize.CENTER; _MyOwnFlexFrameworkTest_TextField1 = temp; mx.binding.BindingManager.executeBindings(this, "_MyOwnFlexFrameworkTest_TextField1", _MyOwnFlexFrameworkTest_TextField1); return temp; } 




Conclusion



I spent this modification today at the end of the lunch break (about 20–30 minutes), of which about 3/4 times were spent on determining where to shove to enter. Do not be afraid to delve into the opensource projects, try to modify them and do better, especially if you have to work with them.



Thank you all for your attention, I will be glad to hear the wishes, about what to write in the next articles of the cycle!

Source: https://habr.com/ru/post/131434/



All Articles