This is an automated email from the ASF dual-hosted git repository. joshtynjala pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
commit 5dde356731d622fecf61720c3b9d321b5bac743f Author: Josh Tynjala <[email protected]> AuthorDate: Tue Dec 12 16:00:34 2023 -0800 MXMLRoyaleEmitter: When writing MXML properties to JS, escape all backslash characters For instance, \n is not a new line in MXML strings. It becomes \\n instead. To insert a real \n new line that won't be modified, use 
 in MXML instead. This is how the Flex SDK compiler behaves, so the Royale compiler now more closely matches Flex. Also cleaned up handling of carriage return and tab characters to match the Flex SDK compiler. --- .../royale/JSRoyaleBasicMXMLDescriptorEmitter.java | 8 +- .../codegen/mxml/royale/MXMLRoyaleEmitter.java | 12 +- .../mxml/royale/TestRoyaleMXMLApplication.java | 1243 ++++++++++++++++++++ .../tree/mxml/MXMLPropertySpecifierNode.java | 11 +- .../internal/tree/mxml/MXMLTreeBuilder.java | 130 +- 5 files changed, 1345 insertions(+), 59 deletions(-) diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java index 934569b89..71698baac 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleBasicMXMLDescriptorEmitter.java @@ -19,6 +19,8 @@ package org.apache.royale.compiler.internal.codegen.js.royale; +import java.util.regex.Matcher; + import org.apache.royale.compiler.codegen.ISubEmitter; import org.apache.royale.compiler.codegen.mxml.js.IMXMLJSEmitter; import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; @@ -244,12 +246,6 @@ public class JSRoyaleBasicMXMLDescriptorEmitter extends MXMLSubEmitter implement { write(ASEmitterTokens.TRUE); writeDelimiter(writeNewline); - // need to do other escaping here? - // restrict="0-9.\" - if (specifier.value.endsWith("\\'") && !specifier.value.endsWith("\\\\'")) - { - specifier.value = specifier.value.substring(0, specifier.value.length() - 1) + "\\'"; - } write(specifier.value); } else diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java index a64f70bfb..2456933d7 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java @@ -3302,11 +3302,19 @@ public class MXMLRoyaleEmitter extends MXMLEmitter implements String s = node.getValue().toString(); if (ps.valueNeedsQuotes) { - // escape all single quotes found within the string + // all backslashes in the value need to be be escaped + // for example: we don't want "\" + "n" to be treated as a new line, + // so it should become "\" + "\" + "n" instead. to insert a new line + // in MXML, use 
 instead. + s = s.replace("\\", "\\\\"); + + // the string will be wrapped with single quotes, so escape all + // existing single quotes found within the string s = s.replace(ASEmitterTokens.SINGLE_QUOTE.getToken(), "\\" + ASEmitterTokens.SINGLE_QUOTE.getToken()); } - s = s.replace("\r\n", "\\n"); + s = s.replace("\t", "\\t"); + s = s.replace("\r", "\\r"); s = s.replace("\n", "\\n"); ps.value += s; diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java index 03b339375..13442c7be 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java @@ -348,6 +348,1249 @@ public class TestRoyaleMXMLApplication extends RoyaleTestBase assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); } + @Test + public void testBackslashTStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"\\t\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\\\t',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testBackslashNStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"\\n\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\\\n',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testBackslashRStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"\\r\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\\\r',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testQuoteEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\""\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\"',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testApostropheEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"'\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\'',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testLessThanEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"<\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '<',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testGreaterThanEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\">\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '>',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testAmpersandEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"&\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '&',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testNewLineEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"
\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\n',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testCarriageReturnEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\" \"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\r',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + + @Test + public void testTabEntityStringAttribute() + { + String code = "<basic:Application xmlns:fx=\"http://ns.adobe.com/mxml/2009\" xmlns:basic=\"library://ns.apache.org/royale/basic\">" + + "<basic:beads><basic:TextPromptBead prompt=\"	\"/></basic:beads></basic:Application>"; + + IMXMLDocumentNode dnode = (IMXMLDocumentNode) getNode(code, + IMXMLDocumentNode.class, RoyaleTestBase.WRAP_LEVEL_NONE); + + ((JSRoyaleEmitter)(mxmlBlockWalker.getASEmitter())).getModel().setCurrentClass(dnode.getDefinition()); + mxmlBlockWalker.visitDocument(dnode); + String appName = dnode.getQualifiedName(); + String outTemplate = "/**\n" + + " * AppName\n" + + " *\n" + + " * @fileoverview\n" + + " *\n" + + " * @suppress {checkTypes|accessControls}\n" + + " */\n" + + "\n" + + "goog.provide('AppName');\n" + + "\n" + + "goog.require('org.apache.royale.core.Application');\n" + + "goog.require('org.apache.royale.html.accessories.TextPromptBead');\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * @constructor\n" + + " * @extends {org.apache.royale.core.Application}\n" + + " */\n" + + "AppName = function() {\n" + + " AppName.base(this, 'constructor');\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {org.apache.royale.html.accessories.TextPromptBead}\n" + + " */\n" + + " this.$ID_8_0;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldd;\n" + + " \n" + + " /**\n" + + " * @private\n" + + " * @type {Array}\n" + + " */\n" + + " this.mxmldp;\n" + + "\n" + + " this.generateMXMLAttributes([\n" + + " 1,\n" + + " 'beads',\n" + + " null,\n" + + " [\n" + + " org.apache.royale.html.accessories.TextPromptBead,\n" + + " 2,\n" + + " '_id',\n" + + " true,\n" + + " '$ID_8_0',\n" + + " 'prompt',\n" + + " true,\n" + + " '\\t',\n" + + " 0,\n" + + " 0,\n" + + " null\n" + + " ],\n" + + " 0,\n" + + " 0\n" + + " ]);\n" + + " \n" + + "};\n" + + "goog.inherits(AppName, org.apache.royale.core.Application);\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Metadata\n" + + " *\n" + + " * @type {Object.<string, Array.<Object>>}\n" + + " */\n" + + "AppName.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'AppName', qName: 'AppName', kind: 'class' }] };\n" + + "\n" + + "\n" + + "\n" + + "/**\n" + + " * Reflection\n" + + " *\n" + + " * @return {Object.<string, Function>}\n" + + " */\n" + + "AppName.prototype.ROYALE_REFLECTION_INFO = function () {\n" + + " return {\n" + + " methods: function () {\n" + + " return {\n" + + " 'AppName': { type: '', declaredBy: 'AppName'}\n"+ + " };\n" + + " }\n" + + " };\n" + + "};\n" + + "/**\n" + + " * @const\n" + + " * @type {number}\n" + + " */\n" + + "AppName.prototype.ROYALE_COMPILE_FLAGS = 9;\n" + + "\n" + + "\n"; + + assertOutWithMetadata(outTemplate.replaceAll("AppName", appName)); + } + @Test public void testInterfaceAttribute() { diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLPropertySpecifierNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLPropertySpecifierNode.java index 64867178c..b6a096b11 100644 --- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLPropertySpecifierNode.java +++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLPropertySpecifierNode.java @@ -221,7 +221,7 @@ class MXMLPropertySpecifierNode extends MXMLSpecifierNodeBase implements IMXMLPr info.addSourceFragments(attribute.getSourcePath(), fragments); // parse out text and make correct kind of child node - processFragments(builder, attribute, info); + processFragments(builder, attribute, info, true); info.clearFragments(); @@ -230,7 +230,8 @@ class MXMLPropertySpecifierNode extends MXMLSpecifierNodeBase implements IMXMLPr private void processFragments(MXMLTreeBuilder builder, ISourceLocation sourceLocation, - MXMLNodeInfo info) + MXMLNodeInfo info, + boolean isAttribute) { ITypeDefinition propertyType = getPropertyType(builder); @@ -256,7 +257,7 @@ class MXMLPropertySpecifierNode extends MXMLSpecifierNodeBase implements IMXMLPr } instanceNode = builder.createInstanceNode( - this, propertyType, fragments, location, flags, classNode); + this, propertyType, fragments, location, flags, classNode, isAttribute); // If we don't have a value, we can't do codegen. if (instanceNode == null) @@ -350,7 +351,7 @@ class MXMLPropertySpecifierNode extends MXMLSpecifierNodeBase implements IMXMLPr // use helpers to set offsets on fragments and create child node of correct type accumulateTextFragments(builder, text, info); - processFragments(builder, text, info); + processFragments(builder, text, info, false); } void initializeDefaultProperty(MXMLTreeBuilder builder, IVariableDefinition defaultPropertyDefinition, @@ -623,7 +624,7 @@ class MXMLPropertySpecifierNode extends MXMLSpecifierNodeBase implements IMXMLPr if (instanceNode == null) { // use helpers for parse for bindings, @functions, create correct child node - processFragments(builder, tag, info); + processFragments(builder, tag, info, false); } validateProperty(builder, tag); diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java index 2672b8b8e..6916a3716 100644 --- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java +++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java @@ -350,7 +350,8 @@ public class MXMLTreeBuilder * <code>null</code>. */ private Object parseValue(IMXMLNode propertyNode, ITypeDefinition type, - String text, EnumSet<TextParsingFlags> flags) + String text, EnumSet<TextParsingFlags> flags, + Object defaultValue, boolean isAttribute) { Object result = null; @@ -359,51 +360,67 @@ public class MXMLTreeBuilder typeName = type.getQualifiedName(); } - if (typeName.equals(IASLanguageConstants.Boolean)) - { - result = mxmlDialect.parseBoolean(project, text, flags); - } - else if (typeName.equals(IASLanguageConstants._int)) - { - result = mxmlDialect.parseInt(project, text, flags); - if (result == null) - result = parsePercent(project, propertyNode, text, flags); - } - else if (typeName.equals(IASLanguageConstants.uint)) - { - result = mxmlDialect.parseUint(project, text, flags); - if (result == null) - result = parsePercent(project, propertyNode, text, flags); - } - else if (typeName.equals(IASLanguageConstants.Number)) - - { - result = mxmlDialect.parseNumber(project, text, flags); - if (result == null) - result = parsePercent(project, propertyNode, text, flags); - } - else if (typeName.equals(IASLanguageConstants.String)) + if (typeName.equals(IASLanguageConstants.String)) { + // for other types below, we always return the default value if the + // text is entirely whitespace, but we preserve the whitespace for + // strings specified with attributes + if (!isAttribute && mxmlDialect.isWhitespace(text)) + { + return defaultValue; + } result = mxmlDialect.parseString(project, text, flags); } - else if (typeName.equals(IASLanguageConstants.Array)) + else { - result = mxmlDialect.parseArray(project, text, flags); - if (result == null && flags.contains(TextParsingFlags.RICH_TEXT_CONTENT)) + // if a non-string value is only whitespace, return the default value + if (mxmlDialect.isWhitespace(text)) { - result = mxmlDialect.parseString(project, text, flags); - if (result != null) + return defaultValue; + } + + if (typeName.equals(IASLanguageConstants.Boolean)) + { + result = mxmlDialect.parseBoolean(project, text, flags); + } + else if (typeName.equals(IASLanguageConstants._int)) + { + result = mxmlDialect.parseInt(project, text, flags); + if (result == null) + result = parsePercent(project, propertyNode, text, flags); + } + else if (typeName.equals(IASLanguageConstants.uint)) + { + result = mxmlDialect.parseUint(project, text, flags); + if (result == null) + result = parsePercent(project, propertyNode, text, flags); + } + else if (typeName.equals(IASLanguageConstants.Number)) + + { + result = mxmlDialect.parseNumber(project, text, flags); + if (result == null) + result = parsePercent(project, propertyNode, text, flags); + } + else if (typeName.equals(IASLanguageConstants.Array)) + { + result = mxmlDialect.parseArray(project, text, flags); + if (result == null && flags.contains(TextParsingFlags.RICH_TEXT_CONTENT)) { - ArrayList<Object> arr = new ArrayList<Object>(); - arr.add(result); - result = arr; + result = mxmlDialect.parseString(project, text, flags); + if (result != null) + { + ArrayList<Object> arr = new ArrayList<Object>(); + arr.add(result); + result = arr; + } } } - } - else if (typeName.equals(IASLanguageConstants.Object) || - typeName.equals(IASLanguageConstants.ANY_TYPE)) - { - result = mxmlDialect.parseObject(project, text, flags); + else if (typeName.equals(IASLanguageConstants.Object) || + typeName.equals(IASLanguageConstants.ANY_TYPE)) + { + result = mxmlDialect.parseObject(project, text, flags); + } } return result; @@ -473,7 +490,8 @@ public class MXMLTreeBuilder ISourceFragment[] fragments, ISourceLocation location, EnumSet<TextParsingFlags> flags, - Object defaultValue) + Object defaultValue, + boolean isAttribute) { Object value = null; if (type.getQualifiedName().equals(IASLanguageConstants.String) @@ -520,9 +538,7 @@ public class MXMLTreeBuilder text = SourceFragmentsReader.concatPhysicalText(fragments); } - value = mxmlDialect.isWhitespace(text) ? - defaultValue : - parseValue(propertyNode, type, text, flags); + value = parseValue(propertyNode, type, text, flags, defaultValue, isAttribute); if (value == null) { @@ -600,6 +616,16 @@ public class MXMLTreeBuilder node.runPostProcess(postProcessSteps, classScope); } + public NodeBase createExpressionNode(IMXMLNode propertyNode, ITypeDefinition type, + ISourceFragment[] fragments, + ISourceLocation location, + EnumSet<TextParsingFlags> flags, + Object defaultValue, + MXMLClassDefinitionNode classNode) + { + return createExpressionNode(propertyNode, type, fragments, location, flags, defaultValue, classNode, false); + } + /** * Creates a databinding node, a class directive node, or a literal node. */ @@ -608,7 +634,8 @@ public class MXMLTreeBuilder ISourceLocation location, EnumSet<TextParsingFlags> flags, Object defaultValue, - MXMLClassDefinitionNode classNode) + MXMLClassDefinitionNode classNode, + boolean isAttribute) { NodeBase expressionNode = null; @@ -659,7 +686,7 @@ public class MXMLTreeBuilder // Look for other primitive values. if (expressionNode == null) - expressionNode = createLiteralNode(propertyNode, type, fragments, location, flags, defaultValue); + expressionNode = createLiteralNode(propertyNode, type, fragments, location, flags, defaultValue, isAttribute); if (expressionNode == null) { @@ -671,6 +698,16 @@ public class MXMLTreeBuilder return expressionNode; } + + public MXMLInstanceNode createInstanceNode(NodeBase parent, ITypeDefinition type, + ISourceFragment[] fragments, + ISourceLocation location, + EnumSet<TextParsingFlags> flags, + MXMLClassDefinitionNode classNode) + { + return createInstanceNode(parent, type, fragments, location, flags, classNode, false); + } + /** * Parses the specified source fragments as a databinding, or a compiler * directive, or a textual value of the specified type and returns an MXML @@ -707,7 +744,8 @@ public class MXMLTreeBuilder ISourceFragment[] fragments, ISourceLocation location, EnumSet<TextParsingFlags> flags, - MXMLClassDefinitionNode classNode) + MXMLClassDefinitionNode classNode, + boolean isAttribute) { MXMLInstanceNode instanceNode = null; @@ -761,7 +799,7 @@ public class MXMLTreeBuilder else { NodeBase expressionNode = createExpressionNode( - (IMXMLNode)parent, type, fragments, location, flags, null, classNode); + (IMXMLNode)parent, type, fragments, location, flags, null, classNode, isAttribute); // If we produced a databinding node or a class directive node, // those are already instance nodes.
