1 package gnu.kawa.functions; 2 import gnu.math.*; 3 import gnu.mapping.*; 4 import gnu.bytecode.*; 5 import gnu.expr.*; 6 import java.math.*; 7 8 9 10 public class NumberCompare extends ProcedureN implements CanInline, Inlineable 11 { 12 Language language; 13 14 static final int RESULT_GRT = 1; 16 static final int RESULT_EQU = 0; 17 static final int RESULT_LSS = -1; 18 static final int RESULT_NAN = -2; 19 static final int RESULT_NEQ = -3; 20 21 public static final int TRUE_IF_GRT = 1 << (RESULT_GRT + 3); 23 public static final int TRUE_IF_EQU = 1 << (RESULT_EQU + 3); 24 public static final int TRUE_IF_LSS = 1 << (RESULT_LSS + 3); 25 public static final int TRUE_IF_NAN = 1 << (RESULT_NAN + 3); 26 public static final int TRUE_IF_NEQ = 1 << (RESULT_NEQ + 3); 27 int flags; 28 29 public int numArgs() { return (-1 << 12) | 2; } 30 31 public static boolean $Eq(Object arg1, Object arg2) 32 { 33 return apply2(TRUE_IF_EQU, arg1, arg2); 34 } 35 36 public static boolean $Gr(Object arg1, Object arg2) 37 { 38 return apply2(TRUE_IF_GRT, arg1, arg2); 39 } 40 41 public static boolean $Gr$Eq(Object arg1, Object arg2) 42 { 43 return apply2(TRUE_IF_GRT|TRUE_IF_EQU, arg1, arg2); 44 } 45 46 public static boolean $Ls(Object arg1, Object arg2) 47 { 48 return apply2(TRUE_IF_LSS, arg1, arg2); 49 } 50 51 public static boolean $Ls$Eq(Object arg1, Object arg2) 52 { 53 return apply2(TRUE_IF_LSS|TRUE_IF_EQU, arg1, arg2); 54 } 55 56 public static boolean $Eq$V (Object arg1, Object arg2, 57 Object arg3, Object [] rest) 58 { 59 return ($Eq(arg1, arg2) && $Eq(arg2, arg3) 60 && (rest.length == 0 61 || ($Eq(arg3, rest[0]) && applyN(TRUE_IF_EQU, rest)))); 62 } 63 64 public static boolean $Gr$V (Object arg1, Object arg2, 65 Object arg3, Object [] rest) 66 { 67 return ($Gr(arg1, arg2) && $Gr(arg2, arg3) 68 && (rest.length == 0 69 || ($Gr(arg3, rest[0]) && applyN(TRUE_IF_GRT, rest)))); 70 } 71 72 public static boolean $Gr$Eq$V (Object arg1, Object arg2, 73 Object arg3, Object [] rest) 74 { 75 return ($Gr$Eq(arg1, arg2) && $Gr$Eq(arg2, arg3) 76 && (rest.length == 0 77 || ($Gr$Eq(arg3, rest[0]) 78 && applyN(TRUE_IF_GRT|TRUE_IF_EQU, rest)))); 79 } 80 81 public static boolean $Ls$V (Object arg1, Object arg2, 82 Object arg3, Object [] rest) 83 { 84 return ($Ls(arg1, arg2) && $Ls(arg2, arg3) 85 && (rest.length == 0 86 || ($Ls(arg3, rest[0]) && applyN(TRUE_IF_LSS, rest)))); 87 } 88 89 public static boolean $Ls$Eq$V (Object arg1, Object arg2, 90 Object arg3, Object [] rest) 91 { 92 return ($Ls$Eq(arg1, arg2) && $Ls$Eq(arg2, arg3) 93 && (rest.length == 0 94 || ($Ls$Eq(arg3, rest[0]) 95 && applyN(TRUE_IF_LSS|TRUE_IF_EQU, rest)))); 96 } 97 98 public static NumberCompare make(Language language, String name, int flags) 99 { 100 NumberCompare proc = new NumberCompare(); 101 proc.language = language; 102 proc.setName(name); 103 proc.flags = flags; 104 return proc; 105 } 106 107 protected final Language getLanguage () 108 { 109 return language; 110 } 111 112 public Object apply2 (Object arg1, Object arg2) 113 { 114 return getLanguage().booleanObject(apply2(flags, arg1, arg2)); 115 } 116 117 static public boolean apply2 (int flags, Object arg1, Object arg2) 118 { 119 return ((1 << (3 + compare(arg1, arg2, true))) & flags) != 0; 120 } 121 122 public static boolean checkCompareCode (int code, int flags) 123 { 124 return ((1 << (3 + code)) & flags) != 0; 125 } 126 127 static public boolean applyWithPromotion (int flags, Object arg1, Object arg2) 128 { 129 return checkCompareCode(compare(arg1, arg2, false), flags); 130 } 131 132 139 static public int compare (Object arg1, Object arg2, boolean exact) 140 { 141 int code1 = Arithmetic.classifyValue(arg1); 142 int code2 = Arithmetic.classifyValue(arg2); 143 return compare(arg1, code1, arg2, code2, exact); 144 } 145 146 static public int compare (Object arg1, int code1, 147 Object arg2, int code2, 148 boolean exact) 149 { 150 if (code1 < 0 || code2 < 0) 151 return -3; 152 int code = code1 < code2 ? code2 : code1; 153 int comp; switch (code) 155 { 156 case Arithmetic.INT_CODE: 157 int i1 = Arithmetic.asInt(arg1); 158 int i2 = Arithmetic.asInt(arg2); 159 comp = i1 < i2 ? -1 : i1 > i2 ? 1 : 0; 160 break; 161 case Arithmetic.LONG_CODE: 162 long l1 = Arithmetic.asLong(arg1); 163 long l2 = Arithmetic.asLong(arg2); 164 comp = l1 < l2 ? -1 : l1 > l2 ? 1 : 0; 165 break; 166 case Arithmetic.BIGINTEGER_CODE: 167 BigInteger bi1 = Arithmetic.asBigInteger(arg1); 168 BigInteger bi2 = Arithmetic.asBigInteger(arg2); 169 comp = bi1.compareTo(bi2); 170 break; 171 case Arithmetic.INTNUM_CODE: 172 comp = IntNum.compare(Arithmetic.asIntNum(arg1), 173 Arithmetic.asIntNum(arg2)); 174 break; 175 case Arithmetic.BIGDECIMAL_CODE: 176 BigDecimal bd1 = Arithmetic.asBigDecimal(arg1); 177 BigDecimal bd2 = Arithmetic.asBigDecimal(arg2); 178 comp = bd1.compareTo(bd2); 179 break; 180 case Arithmetic.RATNUM_CODE: 181 comp = RatNum.compare(Arithmetic.asRatNum(arg1), 182 Arithmetic.asRatNum(arg2)); 183 break; 184 case Arithmetic.FLOAT_CODE: 185 if (! exact 186 || (code1 > Arithmetic.RATNUM_CODE 187 && code2 > Arithmetic.RATNUM_CODE)) 188 { 189 float f1 = Arithmetic.asFloat(arg1); 190 float f2 = Arithmetic.asFloat(arg2); 191 comp = f1 > f2 ? 1 : f1 < f2 ? -1 : f1 == f2 ? 0 : -2; 192 break; 193 } 194 case Arithmetic.DOUBLE_CODE: 196 case Arithmetic.FLONUM_CODE: 197 if (! exact 198 || (code1 > Arithmetic.RATNUM_CODE 199 && code2 > Arithmetic.RATNUM_CODE)) 200 { 201 double d1 = Arithmetic.asDouble(arg1); 202 double d2 = Arithmetic.asDouble(arg2); 203 comp = d1 > d2 ? 1 : d1 < d2 ? -1 : d1 == d2 ? 0 : -2; 204 break; 205 } 206 default: 208 Numeric num1 = Arithmetic.asNumeric(arg1); 209 Numeric num2 = Arithmetic.asNumeric(arg2); 210 comp = ((Numeric) num1).compare(num2); 211 } 212 return comp; 213 } 214 215 static boolean applyN (int flags, Object [] args) 216 { 217 for (int i = 0; i < args.length - 1; i++) 220 { 221 Object arg1 = args[i]; 222 Object arg2 = args[i+1]; 223 if (! apply2(flags, arg1, arg2)) 224 return false; 225 } 226 return true; 227 } 228 229 public Object applyN (Object [] args) 230 { 231 return getLanguage().booleanObject(applyN(flags, args)); 234 } 235 236 public Expression inline (ApplyExp exp, ExpWalker walker) 237 { 238 Expression folded = exp.inlineIfConstant(this, walker); 239 if (folded != exp) 240 return folded; 241 return exp; 242 } 243 244 public void compile (ApplyExp exp, Compilation comp, Target target) 245 { 246 Expression[] args = exp.getArgs(); 247 if (args.length == 2) 248 { 249 Expression arg0 = args[0]; 250 Expression arg1 = args[1]; 251 int kind0 = classify(arg0); 252 int kind1 = classify(arg1); 253 CodeAttr code = comp.getCode(); 254 if (kind0 >= RealNum_KIND && kind1 >= RealNum_KIND 255 && (kind0 != RealNum_KIND || kind1 != RealNum_KIND)) 257 { 258 if (! (target instanceof ConditionalTarget)) 259 { 260 IfExp.compile(exp, QuoteExp.trueExp, QuoteExp.falseExp, 261 comp, target); 262 return; 263 } 264 int mask = flags; 265 if (mask == TRUE_IF_NEQ) 266 mask = TRUE_IF_GRT|TRUE_IF_LSS; 267 if (kind0 >= IntNum_KIND && kind1 >= IntNum_KIND 268 && (kind0 < long_KIND || kind1 < long_KIND)) 269 { 270 Type[] ctypes = new Type[2]; 271 ctypes[0] = AddOp.typeIntNum; 272 if (kind1 >= long_KIND) 273 { 274 ctypes[1] = Type.long_type; 275 } 276 else if (kind0 >= long_KIND 277 && (arg0 instanceof QuoteExp 279 || arg1 instanceof QuoteExp 280 || arg0 instanceof ReferenceExp 281 || arg1 instanceof ReferenceExp)) 282 { 283 ctypes[1] = Type.long_type; 284 args = new Expression[2]; 285 args[0] = arg1; 286 args[1] = arg0; 287 if (mask != TRUE_IF_EQU && mask != TRUE_IF_GRT+TRUE_IF_LSS) 288 mask ^= TRUE_IF_GRT|TRUE_IF_LSS; 289 } 290 else 291 ctypes[1] = AddOp.typeIntNum; 292 Method cmeth 293 = AddOp.typeIntNum.getDeclaredMethod("compare", ctypes); 294 PrimProcedure compare = new PrimProcedure(cmeth); 295 arg0 = new ApplyExp(compare, args); 296 arg1 = new QuoteExp(IntNum.zero()); 297 kind0 = kind1 = int_KIND; 298 } 299 Type commonType; 300 if (kind0 >= int_KIND && kind1 >= int_KIND) 301 commonType = Type.int_type; 302 else if (kind0 >= long_KIND && kind1 >= long_KIND) 303 commonType = Type.long_type; 304 else 305 commonType = Type.double_type; 306 StackTarget subTarget = new StackTarget(commonType); 307 ConditionalTarget ctarget = (ConditionalTarget) target; 308 309 int opcode; 310 if (arg0 instanceof QuoteExp && ! (arg1 instanceof QuoteExp)) 311 { 312 Expression tmp = arg1; arg1 = arg0; arg0 = tmp; 313 if (mask != TRUE_IF_EQU && mask != TRUE_IF_GRT+TRUE_IF_LSS) 314 mask ^= TRUE_IF_GRT|TRUE_IF_LSS; 315 } 316 Label label1 = ctarget.trueBranchComesFirst ? ctarget.ifFalse : ctarget.ifTrue; 317 if (ctarget.trueBranchComesFirst) 318 mask ^= TRUE_IF_GRT|TRUE_IF_LSS|TRUE_IF_EQU; 319 switch (mask) 320 { 321 case TRUE_IF_GRT: opcode = 157 ; break; 322 case TRUE_IF_EQU: opcode = 153 ; break; 323 case TRUE_IF_LSS: opcode = 155 ; break; 324 case TRUE_IF_GRT|TRUE_IF_LSS: opcode = 154 ; break; 325 case TRUE_IF_GRT|TRUE_IF_EQU: opcode = 156 ; break; 326 case TRUE_IF_LSS|TRUE_IF_EQU: opcode = 158 ; break; 327 default: 328 opcode = 0; 329 } 330 arg0.compile(comp, subTarget); 331 Object value; 332 if (kind0 >= int_KIND && kind1 >= int_KIND 333 && arg1 instanceof QuoteExp 334 && (value = ((QuoteExp) arg1).getValue()) instanceof IntNum 335 && ((IntNum) value).isZero()) 336 { 337 code.emitGotoIfCompare1(label1, opcode); 338 } 339 else 340 { 341 arg1.compile(comp, subTarget); 342 code.emitGotoIfCompare2(label1, opcode); 343 } 344 ctarget.emitGotoFirstBranch(code); 345 return; 346 } 347 } 348 ApplyExp.compile(exp, comp, target); 349 } 350 351 private static final int Unknown_KIND = 0; private static final int Number_KIND = 1; private static final int Numeric_KIND = 2; private static final int RealNum_KIND = 3; private static final int double_KIND = 4; private static final int IntNum_KIND = 5; private static final int long_KIND = 6; private static final int int_KIND = 7; 361 static int classify (Expression exp) 362 { 363 Type type = exp.getType(); 364 int kind = classify(type); 365 Object value; 366 if (kind == IntNum_KIND && exp instanceof QuoteExp 367 && (value = ((QuoteExp) exp).getValue()) instanceof IntNum) 368 { 369 int ilength = ((IntNum) value).intLength(); 370 if (ilength < 32) 371 return int_KIND; 372 if (ilength < 64) 373 return long_KIND; 374 } 375 return kind; 376 } 377 378 static int classify (Type type) 379 { 380 if (type instanceof PrimType) 381 { 382 char sig = type.getSignature().charAt(0); 383 if (sig == 'V' || sig == 'Z' || sig == 'C') 384 return Unknown_KIND; 385 if (sig == 'D' || sig == 'F') 386 return double_KIND; 387 if (sig == 'J') 388 return long_KIND; 389 return int_KIND; 390 } 391 if (type.isSubtype(AddOp.typeIntNum)) 392 return IntNum_KIND; 393 if (type.isSubtype(AddOp.typeDFloNum)) 394 return double_KIND; 395 if (type.isSubtype(AddOp.typeRealNum)) 396 return RealNum_KIND; 397 if (type.isSubtype(AddOp.typeNumeric)) 398 return Numeric_KIND; 399 return Unknown_KIND; 400 } 401 402 public Type getReturnType (Expression[] args) 403 { 404 return Compilation.scmBooleanType; 405 } 406 } 407 | Popular Tags |