fix promotion for constructor functions
add tests for constructor functions
implement review comments
diff --git a/asterix-app/data/type_promotion.adm b/asterix-app/data/type_promotion.adm
index 5a120d4..a3477c1 100644
--- a/asterix-app/data/type_promotion.adm
+++ b/asterix-app/data/type_promotion.adm
@@ -30,6 +30,15 @@
 }
 {
   "id": 3,
+  "int8":   int8("100"),
+  "int16":  int16("10000"),
+  "int32":  int16("10000"),
+  "int64":  int16("10000"),
+  "float":  int16("10000"),
+  "double": int16("10000")
+}
+{
+  "id": 4,
   "int8":   100i8,
   "int16":  10000i16,
   "int32":  1000000i32,
@@ -38,7 +47,16 @@
   "double": 1000000i32
 }
 {
-  "id": 4,
+  "id": 5,
+  "int8":   int8("100"),
+  "int16":  int16("10000"),
+  "int32":  int32("1000000"),
+  "int64":  int32("1000000"),
+  "float":  int32("1000000"),
+  "double": int32("1000000")
+}
+{
+  "id": 6,
   "int8":   100i8,
   "int16":  10000i16,
   "int32":  1000000,
@@ -47,7 +65,25 @@
   "double": 1000000
 }
 {
-  "id": 5,
+  "id": 7,
+  "int8":   100i8,
+  "int16":  10000i16,
+  "int32":  1000000i32,
+  "int64":  10000000000i64,
+  "float":  1000000i32,
+  "double": 10000000000i64
+}
+{
+  "id": 8,
+  "int8":   int8("100"),
+  "int16":  int16("10000"),
+  "int32":  int32("1000000"),
+  "int64":  int64("10000000000"),
+  "float":  int32("1000000"),
+  "double": int64("10000000000")
+}
+{
+  "id": 9,
   "int8":   100i8,
   "int16":  10000i16,
   "int32":  1000000,
diff --git a/asterix-app/src/test/resources/runtimets/results/load/type_promotion_0/type_promotion_0.1.adm b/asterix-app/src/test/resources/runtimets/results/load/type_promotion_0/type_promotion_0.1.adm
index 7b0720f..10b0c92 100644
--- a/asterix-app/src/test/resources/runtimets/results/load/type_promotion_0/type_promotion_0.1.adm
+++ b/asterix-app/src/test/resources/runtimets/results/load/type_promotion_0/type_promotion_0.1.adm
@@ -1,5 +1,9 @@
 { "id": 1i64, "int8": 100i8, "int16": 100i16, "int32": 100, "int64": 100i64, "float": 100.0f, "double": 100.0d, "int8_u": {{ 100i8 }}, "int8_o": [ 100i8 ], "int16_u": {{ 100i16, 10000i16 }}, "int16_o": [ 100i16, 10000i16 ], "int32_u": {{ 100, 10000, 1000000, 1000000 }}, "int32_o": [ 100, 10000, 1000000, 1000000 ], "int64_u": {{ 100i64, 10000i64, 1000000i64, 1000000i64, 10000000000i64 }}, "int64_o": [ 100i64, 10000i64, 1000000i64, 1000000i64, 10000000000i64 ], "float_u": {{ 100.0f, 10000.0f, 1000000.0f, 1000000.0f }}, "float_o": [ 100.0f, 10000.0f, 1000000.0f, 1000000.0f ], "double_u": {{ 100.0d, 10000.0d, 1000000.0d, 1000000.0d, 1.0E10d }}, "double_o": [ 100.0d, 10000.0d, 1000000.0d, 1000000.0d, 1.0E10d ] }
 { "id": 2i64, "int8": 100i8, "int16": 10000i16, "int32": 10000, "int64": 10000i64, "float": 10000.0f, "double": 10000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
-{ "id": 3i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 1000000i64, "float": 1000000.0f, "double": 1000000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 3i64, "int8": 100i8, "int16": 10000i16, "int32": 10000, "int64": 10000i64, "float": 10000.0f, "double": 10000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
 { "id": 4i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 1000000i64, "float": 1000000.0f, "double": 1000000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
-{ "id": 5i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 10000000000i64, "float": 1000000.0f, "double": 1.0E10d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 5i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 1000000i64, "float": 1000000.0f, "double": 1000000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 6i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 1000000i64, "float": 1000000.0f, "double": 1000000.0d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 7i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 10000000000i64, "float": 1000000.0f, "double": 1.0E10d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 8i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 10000000000i64, "float": 1000000.0f, "double": 1.0E10d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
+{ "id": 9i64, "int8": 100i8, "int16": 10000i16, "int32": 1000000, "int64": 10000000000i64, "float": 1000000.0f, "double": 1.0E10d, "int8_u": null, "int8_o": null, "int16_u": null, "int16_o": null, "int32_u": null, "int32_o": null, "int64_u": null, "int64_o": null, "float_u": null, "float_o": null, "double_u": null, "double_o": null }
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/operators/file/ADMDataParser.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/operators/file/ADMDataParser.java
index 26a6584..848a124 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/operators/file/ADMDataParser.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/operators/file/ADMDataParser.java
@@ -143,7 +143,7 @@
                 break;
             }
             case AdmLexer.TOKEN_DOUBLE_LITERAL: {
-                parseToTarget(ATypeTag.DOUBLE, objectType, out);
+                parseToNumericTarget(ATypeTag.DOUBLE, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_DOUBLE_CONS: {
@@ -151,7 +151,7 @@
                 break;
             }
             case AdmLexer.TOKEN_FLOAT_LITERAL: {
-                parseToTarget(ATypeTag.FLOAT, objectType, out);
+                parseToNumericTarget(ATypeTag.FLOAT, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_FLOAT_CONS: {
@@ -159,7 +159,7 @@
                 break;
             }
             case AdmLexer.TOKEN_INT8_LITERAL: {
-                parseAndCast(ATypeTag.INT8, objectType, out);
+                parseAndCastNumeric(ATypeTag.INT8, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_INT8_CONS: {
@@ -167,7 +167,7 @@
                 break;
             }
             case AdmLexer.TOKEN_INT16_LITERAL: {
-                parseAndCast(ATypeTag.INT16, objectType, out);
+                parseAndCastNumeric(ATypeTag.INT16, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_INT16_CONS: {
@@ -175,11 +175,11 @@
                 break;
             }
             case AdmLexer.TOKEN_INT_LITERAL:{
-                parseToTarget(ATypeTag.INT32, objectType, out);
+                parseToNumericTarget(ATypeTag.INT32, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_INT32_LITERAL: {
-                parseAndCast(ATypeTag.INT32, objectType, out);
+                parseAndCastNumeric(ATypeTag.INT32, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_INT32_CONS: {
@@ -187,7 +187,7 @@
                 break;
             }
             case AdmLexer.TOKEN_INT64_LITERAL: {
-                parseAndCast(ATypeTag.INT64, objectType, out);
+                parseAndCastNumeric(ATypeTag.INT64, objectType, out);
                 break;
             }
             case AdmLexer.TOKEN_INT64_CONS: {
@@ -397,7 +397,7 @@
 
     List<IAType> unionList;
 
-    private ATypeTag getTargetTypeTag(ATypeTag expectedTypeTag, IAType aObjectType, DataOutput out) throws IOException {
+    private ATypeTag getTargetTypeTag(ATypeTag expectedTypeTag, IAType aObjectType) throws IOException {
         if (aObjectType == null) {
             return expectedTypeTag;
         }
@@ -417,7 +417,7 @@
     }
     
     private boolean checkType(ATypeTag expectedTypeTag, IAType aObjectType, DataOutput out) throws IOException {
-        return getTargetTypeTag(expectedTypeTag, aObjectType, out) != null;
+        return getTargetTypeTag(expectedTypeTag, aObjectType) != null;
     }
 
     private void parseRecord(ARecordType recType, DataOutput out, Boolean datasetRec) throws IOException,
@@ -718,52 +718,25 @@
         baaosPool.add(tempBaaos);
     }
 
-    private boolean parseNumeric(final ATypeTag typeTag, DataOutput out) throws HyracksDataException,
-            AsterixException {
-        switch (typeTag) {
-            case DOUBLE:
-                aDouble.setValue(Double.parseDouble(admLexer.getLastTokenImage()));
-                doubleSerde.serialize(aDouble, out);
-                return true;
-            case FLOAT:
-                aFloat.setValue(Float.parseFloat(admLexer.getLastTokenImage()));
-                floatSerde.serialize(aFloat, out);
-                return true;
-            case INT8:
-                parseInt8(admLexer.getLastTokenImage(), out);
-                return true;
-            case INT16:
-                parseInt16(admLexer.getLastTokenImage(), out);
-                return true;
-            case INT32:
-                parseInt32(admLexer.getLastTokenImage(), out);
-                return true;
-            case INT64:
-                parseInt64(admLexer.getLastTokenImage(), out);
-                return true;
-            default: // fall through
-        }
-        return false;
-    }
 
-    private void parseToTarget(ATypeTag typeTag, IAType objectType, DataOutput out) throws AsterixException,
+    private void parseToNumericTarget(ATypeTag typeTag, IAType objectType, DataOutput out) throws AsterixException,
             IOException {
-        final ATypeTag targetTypeTag = getTargetTypeTag(typeTag, objectType, out);
-        if (targetTypeTag == null || !parseNumeric(targetTypeTag, out)) {
+        final ATypeTag targetTypeTag = getTargetTypeTag(typeTag, objectType);
+        if (targetTypeTag == null || !parseValue(admLexer.getLastTokenImage(), targetTypeTag, out)) {
             throw new AsterixException(mismatchErrorMessage + objectType.getTypeName() + mismatchErrorMessage2
                     + typeTag);
         }
     }
     
-    private void parseAndCast(ATypeTag typeTag, IAType objectType, DataOutput out) throws AsterixException, IOException {
-        final ATypeTag targetTypeTag = getTargetTypeTag(typeTag, objectType, out);
+    private void parseAndCastNumeric(ATypeTag typeTag, IAType objectType, DataOutput out) throws AsterixException, IOException {
+        final ATypeTag targetTypeTag = getTargetTypeTag(typeTag, objectType);
         DataOutput dataOutput = out;
         if (targetTypeTag != typeTag) {
             castBuffer.reset();
             dataOutput = castBuffer.getDataOutput();
         }
 
-        if (targetTypeTag == null || !parseNumeric(typeTag, dataOutput)) {
+        if (targetTypeTag == null || !parseValue(admLexer.getLastTokenImage(), typeTag, dataOutput)) {
             throw new AsterixException(mismatchErrorMessage + objectType.getTypeName() + mismatchErrorMessage2
                     + typeTag);
         }
@@ -780,129 +753,115 @@
     
     private void parseConstructor(ATypeTag typeTag, IAType objectType, DataOutput out) throws AsterixException {
         try {
-            int token = admLexer.next();
-            if (token == AdmLexer.TOKEN_CONSTRUCTOR_OPEN) {
-                if (checkType(typeTag, objectType, out)) {
+            final ATypeTag targetTypeTag = getTargetTypeTag(typeTag, objectType);
+            if (targetTypeTag != null) {
+                DataOutput dataOutput = out;
+                if (targetTypeTag != typeTag) {
+                    castBuffer.reset();
+                    dataOutput = castBuffer.getDataOutput();
+                }
+                int token = admLexer.next();
+                if (token == AdmLexer.TOKEN_CONSTRUCTOR_OPEN) {
                     token = admLexer.next();
                     if (token == AdmLexer.TOKEN_STRING_LITERAL) {
-                        switch (typeTag) {
-                            case BOOLEAN:
-                                parseBoolean(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case INT8:
-                                parseInt8(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case INT16:
-                                parseInt16(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case INT32:
-                                parseInt32(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case INT64:
-                                parseInt64(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case FLOAT:
-                                aFloat.setValue(Float.parseFloat(admLexer.getLastTokenImage().substring(1,
-                                        admLexer.getLastTokenImage().length() - 1)));
-                                floatSerde.serialize(aFloat, out);
-                                break;
-                            case DOUBLE:
-                                aDouble.setValue(Double.parseDouble(admLexer.getLastTokenImage().substring(1,
-                                        admLexer.getLastTokenImage().length() - 1)));
-                                doubleSerde.serialize(aDouble, out);
-                                break;
-                            case STRING:
-                                aString.setValue(admLexer.getLastTokenImage().substring(1,
-                                        admLexer.getLastTokenImage().length() - 1));
-                                stringSerde.serialize(aString, out);
-                                break;
-                            case TIME:
-                                parseTime(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case DATE:
-                                parseDate(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case DATETIME:
-                                parseDatetime(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case DURATION:
-                                parseDuration(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case DAYTIMEDURATION:
-                                parseDayTimeDuration(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case YEARMONTHDURATION:
-                                parseYearMonthDuration(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case POINT:
-                                parsePoint(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case POINT3D:
-                                parsePoint3d(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case CIRCLE:
-                                parseCircle(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case RECTANGLE:
-                                parseRectangle(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case LINE:
-                                parseLine(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            case POLYGON:
-                                parsePolygon(
-                                        admLexer.getLastTokenImage().substring(1,
-                                                admLexer.getLastTokenImage().length() - 1), out);
-                                break;
-                            default:
-                                throw new AsterixException("Missing deserializer method for constructor: "
-                                        + AdmLexer.tokenKindToString(token) + ".");
-
+                        final String unquoted = admLexer.getLastTokenImage().substring(1,
+                                admLexer.getLastTokenImage().length() - 1);
+                        if (!parseValue(unquoted, typeTag, dataOutput)) {
+                            throw new AsterixException("Missing deserializer method for constructor: "
+                                    + AdmLexer.tokenKindToString(token) + ".");
                         }
                         token = admLexer.next();
-                        if (token == AdmLexer.TOKEN_CONSTRUCTOR_CLOSE)
+                        if (token == AdmLexer.TOKEN_CONSTRUCTOR_CLOSE) {
+                            if (targetTypeTag != typeTag) {
+                                ITypePromoteComputer promoteComputer = ATypeHierarchy.getTypePromoteComputer(typeTag, targetTypeTag);
+                                // the availability if the promote computer should be consistent with the availability of a target type
+                                assert promoteComputer != null;
+                                // do the promotion; note that the type tag field should be skipped
+                                promoteComputer.promote(castBuffer.getByteArray(), castBuffer.getStartOffset() + 1,
+                                        castBuffer.getLength() - 1, out);
+                            }
                             return;
+                        }
                     }
                 }
             }
-        } catch (Exception e) {
+        } catch (IOException | AdmLexerException e) {
             throw new AsterixException(e);
         }
         throw new AsterixException(mismatchErrorMessage + objectType.getTypeName() + ". Got " + typeTag + " instead.");
     }
 
+    private boolean parseValue(final String unquoted, ATypeTag typeTag, DataOutput out)
+            throws AsterixException, HyracksDataException, IOException {
+        switch (typeTag) {
+            case BOOLEAN:
+                parseBoolean(unquoted, out);
+                return true;
+            case INT8:
+                parseInt8(unquoted, out);
+                return true;
+            case INT16:
+                parseInt16(unquoted, out);
+                return true;
+            case INT32:
+                parseInt32(unquoted, out);
+                return true;
+            case INT64:
+                parseInt64(unquoted, out);
+                return true;
+            case FLOAT:
+                aFloat.setValue(Float.parseFloat(unquoted));
+                floatSerde.serialize(aFloat, out);
+                return true;
+            case DOUBLE:
+                aDouble.setValue(Double.parseDouble(unquoted));
+                doubleSerde.serialize(aDouble, out);
+                return true;
+            case STRING:
+                aString.setValue(unquoted);
+                stringSerde.serialize(aString, out);
+                return true;
+            case TIME:
+                parseTime(unquoted, out);
+                return true;
+            case DATE:
+                parseDate(unquoted, out);
+                return true;
+            case DATETIME:
+                parseDatetime(unquoted, out);
+                return true;
+            case DURATION:
+                parseDuration(unquoted, out);
+                return true;
+            case DAYTIMEDURATION:
+                parseDayTimeDuration(unquoted, out);
+                return true;
+            case YEARMONTHDURATION:
+                parseYearMonthDuration(unquoted, out);
+                return true;
+            case POINT:
+                parsePoint(unquoted, out);
+                return true;
+            case POINT3D:
+                parsePoint3d(unquoted, out);
+                return true;
+            case CIRCLE:
+                parseCircle(unquoted, out);
+                return true;
+            case RECTANGLE:
+                parseRectangle(unquoted, out);
+                return true;
+            case LINE:
+                parseLine(unquoted, out);
+                return true;
+            case POLYGON:
+                parsePolygon(unquoted, out);
+                return true;
+            default:
+                return false;
+        }
+    }
+
     private void parseBoolean(String bool, DataOutput out) throws AsterixException {
         String errorMessage = "This can not be an instance of boolean";
         try {