1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.treetank.service.xml.xpath.operators;
29
30 import org.treetank.api.INodeReadTrx;
31 import org.treetank.axis.AbsAxis;
32 import org.treetank.exception.TTXPathException;
33 import org.treetank.node.AtomicValue;
34 import org.treetank.node.Type;
35 import org.treetank.service.xml.xpath.EXPathError;
36 import org.treetank.utils.NamePageHash;
37 import org.treetank.utils.TypedValue;
38
39
40
41
42
43
44
45 public class AddOpAxis extends AbsObAxis {
46
47
48
49
50
51
52
53
54
55
56
57 public AddOpAxis(final INodeReadTrx rtx, final AbsAxis mOp1, final AbsAxis mOp2) {
58
59 super(rtx, mOp1, mOp2);
60 }
61
62
63
64
65
66 @Override
67 public AtomicValue operate(final AtomicValue mOperand1, final AtomicValue mOperand2)
68 throws TTXPathException {
69
70 final Type returnType = getReturnType(mOperand1.getTypeKey(), mOperand2.getTypeKey());
71 final int typeKey = NamePageHash.generateHashForString(returnType.getStringRepr());
72
73 final byte[] value;
74
75 switch (returnType) {
76 case DOUBLE:
77 case FLOAT:
78 case DECIMAL:
79 case INTEGER:
80 final double dOp1 = Double.parseDouble(new String(mOperand1.getRawValue()));
81 final double dOp2 = Double.parseDouble(new String(mOperand2.getRawValue()));
82 value = TypedValue.getBytes(dOp1 + dOp2);
83 break;
84 case DATE:
85 case TIME:
86 case DATE_TIME:
87 case YEAR_MONTH_DURATION:
88 case DAY_TIME_DURATION:
89 throw new IllegalStateException("Add operator is not implemented for the type "
90 + returnType.getStringRepr() + " yet.");
91 default:
92 throw EXPathError.XPTY0004.getEncapsulatedException();
93
94 }
95
96 return new AtomicValue(value, typeKey);
97
98 }
99
100
101
102
103
104 @Override
105 protected Type getReturnType(final int mOp1, final int mOp2) throws TTXPathException {
106
107 final Type mType1 = Type.getType(mOp1).getPrimitiveBaseType();
108 final Type mType2 = Type.getType(mOp2).getPrimitiveBaseType();
109
110 if (mType1.isNumericType() && mType2.isNumericType()) {
111
112
113 if (mType1 == mType2) {
114 return mType1;
115 } else if (mType1 == Type.DOUBLE || mType2 == Type.DOUBLE) {
116 return Type.DOUBLE;
117 } else if (mType1 == Type.FLOAT || mType2 == Type.FLOAT) {
118 return Type.FLOAT;
119 } else {
120 assert (mType1 == Type.DECIMAL || mType2 == Type.DECIMAL);
121 return Type.DECIMAL;
122 }
123
124 } else {
125
126 switch (mType1) {
127 case DATE:
128 if (mType2 == Type.YEAR_MONTH_DURATION || mType2 == Type.DAY_TIME_DURATION) {
129 return mType1;
130 }
131 break;
132 case TIME:
133 if (mType2 == Type.DAY_TIME_DURATION) {
134 return mType1;
135 }
136 break;
137 case DATE_TIME:
138 if (mType2 == Type.YEAR_MONTH_DURATION || mType2 == Type.DAY_TIME_DURATION) {
139 return mType1;
140 }
141 break;
142 case YEAR_MONTH_DURATION:
143 if (mType2 == Type.DATE || mType2 == Type.DATE_TIME || mType2 == Type.YEAR_MONTH_DURATION) {
144 return mType2;
145 }
146 break;
147 case DAY_TIME_DURATION:
148 if (mType2 == Type.DATE || mType2 == Type.TIME || mType2 == Type.DATE_TIME
149 || mType2 == Type.DAY_TIME_DURATION) {
150 return mType2;
151 }
152 break;
153 default:
154 throw EXPathError.XPTY0004.getEncapsulatedException();
155 }
156 throw EXPathError.XPTY0004.getEncapsulatedException();
157 }
158 }
159
160 }