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.XPathError;
36 import org.treetank.service.xml.xpath.XPathError.ErrorType;
37 import org.treetank.utils.NamePageHash;
38 import org.treetank.utils.TypedValue;
39
40
41
42
43
44
45
46 public class ModOpAxis extends AbsObAxis {
47
48
49
50
51
52
53
54
55
56
57
58 public ModOpAxis(final INodeReadTrx rtx, final AbsAxis mOp1, final AbsAxis mOp2) {
59
60 super(rtx, mOp1, mOp2);
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 final double dOp1 = Double.parseDouble(new String(mOperand1.getRawValue()));
80 final double dOp2 = Double.parseDouble(new String(mOperand2.getRawValue()));
81 value = TypedValue.getBytes(dOp1 % dOp2);
82 break;
83 case INTEGER:
84 try {
85 final int iOp1 = (int)Double.parseDouble(new String(mOperand1.getRawValue()));
86 final int iOp2 = (int)Double.parseDouble(new String(mOperand2.getRawValue()));
87 value = TypedValue.getBytes(iOp1 % iOp2);
88 } catch (final ArithmeticException e) {
89 throw new XPathError(ErrorType.FOAR0001);
90 }
91 break;
92 default:
93 throw new XPathError(ErrorType.XPTY0004);
94
95 }
96
97 return new AtomicValue(value, typeKey);
98
99 }
100
101
102
103
104 @Override
105 protected Type getReturnType(final int mOp1, final int mOp2) throws TTXPathException {
106 Type type1;
107 Type type2;
108 try {
109 type1 = Type.getType(mOp1).getPrimitiveBaseType();
110 type2 = Type.getType(mOp2).getPrimitiveBaseType();
111 } catch (IllegalStateException e) {
112 throw new XPathError(ErrorType.XPTY0004);
113 }
114
115
116 if (type1.isNumericType() && type2.isNumericType()) {
117
118
119 if (type1 == type2) {
120 return type1;
121 }
122
123 if (type1 == Type.DOUBLE || type2 == Type.DOUBLE) {
124 return Type.DOUBLE;
125 } else if (type1 == Type.FLOAT || type2 == Type.FLOAT) {
126 return Type.FLOAT;
127 } else {
128 assert (type1 == Type.DECIMAL || type2 == Type.DECIMAL);
129 return Type.DECIMAL;
130 }
131
132 } else {
133 throw new XPathError(ErrorType.XPTY0004);
134 }
135 }
136
137 }