001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#151 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2002-2002 Kana Software, Inc. 007 // Copyright (C) 2002-2008 Julian Hyde and others 008 // All Rights Reserved. 009 // You must accept the terms of that agreement to use this software. 010 // 011 // jhyde, 26 February, 2002 012 */ 013 package mondrian.olap.fun; 014 015 import mondrian.calc.*; 016 import mondrian.calc.impl.*; 017 import mondrian.mdx.DimensionExpr; 018 import mondrian.mdx.ResolvedFunCall; 019 import mondrian.olap.*; 020 import mondrian.olap.Member; 021 import mondrian.olap.fun.extra.NthQuartileFunDef; 022 import mondrian.olap.fun.extra.CalculatedChildFunDef; 023 import mondrian.olap.fun.vba.Vba; 024 import mondrian.olap.fun.vba.Excel; 025 import mondrian.olap.type.DimensionType; 026 import mondrian.olap.type.LevelType; 027 import mondrian.olap.type.Type; 028 import org.eigenbase.xom.XOMUtil; 029 030 import java.io.PrintWriter; 031 import java.util.*; 032 033 /** 034 * <code>BuiltinFunTable</code> contains a list of all built-in MDX functions. 035 * 036 * <p>Note: Boolean expressions return {@link Boolean#TRUE}, 037 * {@link Boolean#FALSE} or null. null is returned if the expression can not be 038 * evaluated because some values have not been loaded from database yet.</p> 039 * 040 * @author jhyde 041 * @since 26 February, 2002 042 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/BuiltinFunTable.java#151 $ 043 */ 044 public class BuiltinFunTable extends FunTableImpl { 045 046 /** the singleton */ 047 private static BuiltinFunTable instance; 048 049 /** 050 * Creates a function table containing all of the builtin MDX functions. 051 * This method should only be called from {@link BuiltinFunTable#instance}. 052 */ 053 protected BuiltinFunTable() { 054 super(); 055 } 056 057 protected void defineFunctions() { 058 defineReserved("NULL"); 059 060 // Empty expression 061 define( 062 new FunDefBase( 063 "", 064 "", 065 "Dummy function representing the empty expression", 066 Syntax.Empty, 067 Category.Empty, 068 new int[0]) { 069 070 } 071 ); 072 073 // first char: p=Property, m=Method, i=Infix, P=Prefix 074 // 2nd: 075 076 // ARRAY FUNCTIONS 077 078 // "SetToArray(<Set>[, <Set>]...[, <Numeric Expression>])" 079 if (false) define(new FunDefBase( 080 "SetToArray", 081 "SetToArray(<Set>[, <Set>]...[, <Numeric Expression>])", 082 "Converts one or more sets to an array for use in a user-defined function.", 083 "fa*") { 084 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 085 throw new UnsupportedOperationException(); 086 } 087 }); 088 089 // 090 // DIMENSION FUNCTIONS 091 define(HierarchyDimensionFunDef.instance); 092 093 // "<Dimension>.Dimension" 094 define(new FunDefBase( 095 "Dimension", 096 "Returns the dimension that contains a specified hierarchy.", 097 "pdd") { 098 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 099 Dimension dimension = 100 ((DimensionExpr) call.getArg(0)).getDimension(); 101 return new ConstantCalc( 102 DimensionType.forDimension(dimension), 103 dimension); 104 } 105 106 }); 107 108 // "<Level>.Dimension" 109 define(new FunDefBase( 110 "Dimension", 111 "Returns the dimension that contains a specified level.", 112 "pdl") { 113 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 114 final LevelCalc levelCalc = 115 compiler.compileLevel(call.getArg(0)); 116 return new AbstractDimensionCalc(call, new Calc[] {levelCalc}) { 117 public Dimension evaluateDimension(Evaluator evaluator) { 118 Level level = levelCalc.evaluateLevel(evaluator); 119 return level.getDimension(); 120 } 121 }; 122 } 123 }); 124 125 // "<Member>.Dimension" 126 define(new FunDefBase( 127 "Dimension", 128 "Returns the dimension that contains a specified member.", 129 "pdm") { 130 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 131 final MemberCalc memberCalc = 132 compiler.compileMember(call.getArg(0)); 133 return new AbstractDimensionCalc(call, new Calc[] {memberCalc}) { 134 public Dimension evaluateDimension(Evaluator evaluator) { 135 Member member = memberCalc.evaluateMember(evaluator); 136 return member.getDimension(); 137 } 138 }; 139 } 140 }); 141 142 // "Dimensions(<Numeric Expression>)" 143 define(new FunDefBase( 144 "Dimensions", 145 "Returns the dimension whose zero-based position within the cube is specified by a numeric expression.", 146 "fdn") { 147 public Type getResultType(Validator validator, Exp[] args) { 148 return DimensionType.Unknown; 149 } 150 151 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 152 final IntegerCalc integerCalc = 153 compiler.compileInteger(call.getArg(0)); 154 return new AbstractDimensionCalc(call, new Calc[] {integerCalc}) { 155 public Dimension evaluateDimension(Evaluator evaluator) { 156 int n = integerCalc.evaluateInteger(evaluator); 157 return nthDimension(evaluator, n); 158 } 159 }; 160 } 161 162 Dimension nthDimension(Evaluator evaluator, int n) { 163 Cube cube = evaluator.getCube(); 164 Dimension[] dimensions = cube.getDimensions(); 165 if (n >= dimensions.length || n < 0) { 166 throw newEvalException( 167 this, "Index '" + n + "' out of bounds"); 168 } 169 return dimensions[n]; 170 } 171 }); 172 173 // "Dimensions(<String Expression>)" 174 define(new FunDefBase( 175 "Dimensions", 176 "Returns the dimension whose name is specified by a string.", 177 "fdS") { 178 public Type getResultType(Validator validator, Exp[] args) { 179 return DimensionType.Unknown; 180 } 181 182 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 183 final StringCalc stringCalc = 184 compiler.compileString(call.getArg(0)); 185 return new AbstractDimensionCalc(call, new Calc[] {stringCalc}) { 186 public Dimension evaluateDimension(Evaluator evaluator) { 187 String dimensionName = 188 stringCalc.evaluateString(evaluator); 189 return findDimension(dimensionName, evaluator); 190 } 191 }; 192 } 193 194 Dimension findDimension(String s, Evaluator evaluator) { 195 if (s.indexOf("[") == -1) { 196 s = Util.quoteMdxIdentifier(s); 197 } 198 OlapElement o = evaluator.getSchemaReader().lookupCompound( 199 evaluator.getCube(), 200 parseIdentifier(s), 201 false, 202 Category.Dimension); 203 if (o instanceof Dimension) { 204 return (Dimension) o; 205 } else if (o == null) { 206 throw newEvalException(this, "Dimension '" + s + "' not found"); 207 } else { 208 throw newEvalException(this, "Dimensions(" + s + ") found " + o); 209 } 210 } 211 }); 212 213 // 214 // HIERARCHY FUNCTIONS 215 define(LevelHierarchyFunDef.instance); 216 define(MemberHierarchyFunDef.instance); 217 218 // 219 // LEVEL FUNCTIONS 220 define(MemberLevelFunDef.instance); 221 222 // "<Hierarchy>.Levels(<Numeric Expression>)" 223 define(new FunDefBase( 224 "Levels", 225 "Returns the level whose position in a hierarchy is specified by a numeric expression.", 226 "mlhn") { 227 public Type getResultType(Validator validator, Exp[] args) { 228 final Type argType = args[0].getType(); 229 return LevelType.forType(argType); 230 } 231 232 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 233 final HierarchyCalc hierarchyCalc = 234 compiler.compileHierarchy(call.getArg(0)); 235 final IntegerCalc ordinalCalc = 236 compiler.compileInteger(call.getArg(1)); 237 return new AbstractLevelCalc(call, new Calc[] {hierarchyCalc, ordinalCalc}) { 238 public Level evaluateLevel(Evaluator evaluator) { 239 Hierarchy hierarchy = 240 hierarchyCalc.evaluateHierarchy(evaluator); 241 int ordinal = ordinalCalc.evaluateInteger(evaluator); 242 return nthLevel(hierarchy, ordinal); 243 } 244 }; 245 } 246 247 Level nthLevel(Hierarchy hierarchy, int n) { 248 Level[] levels = hierarchy.getLevels(); 249 250 if (n >= levels.length || n < 0) { 251 throw newEvalException( 252 this, "Index '" + n + "' out of bounds"); 253 } 254 return levels[n]; 255 } 256 }); 257 258 // "<Hierarchy>.Levels(<String Expression>)" 259 define(new FunDefBase( 260 "Levels", 261 "Returns the level whose name is specified by a string expression.", 262 "mlhS") { 263 public Type getResultType(Validator validator, Exp[] args) { 264 final Type argType = args[0].getType(); 265 return LevelType.forType(argType); 266 } 267 268 public Calc compileCall( 269 final ResolvedFunCall call, ExpCompiler compiler) 270 { 271 final HierarchyCalc hierarchyCalc = 272 compiler.compileHierarchy(call.getArg(0)); 273 final StringCalc nameCalc = 274 compiler.compileString(call.getArg(1)); 275 return new AbstractLevelCalc( 276 call, new Calc[] {hierarchyCalc, nameCalc}) { 277 public Level evaluateLevel(Evaluator evaluator) { 278 Hierarchy hierarchy = 279 hierarchyCalc.evaluateHierarchy(evaluator); 280 String name = nameCalc.evaluateString(evaluator); 281 for (Level level : hierarchy.getLevels()) { 282 if (level.getName().equals(name)) { 283 return level; 284 } 285 } 286 throw newEvalException( 287 call.getFunDef(), 288 "Level '" + name + "' not found in hierarchy '" 289 + hierarchy + "'"); 290 } 291 }; 292 } 293 }); 294 295 // "Levels(<String Expression>)" 296 define(new FunDefBase( 297 "Levels", 298 "Returns the level whose name is specified by a string expression.", 299 "flS") { 300 public Type getResultType(Validator validator, Exp[] args) { 301 final Type argType = args[0].getType(); 302 return LevelType.forType(argType); 303 } 304 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 305 final StringCalc stringCalc = 306 compiler.compileString(call.getArg(0)); 307 return new AbstractLevelCalc(call, new Calc[] {stringCalc}) { 308 public Level evaluateLevel(Evaluator evaluator) { 309 String levelName = 310 stringCalc.evaluateString(evaluator); 311 return findLevel(evaluator, levelName); 312 } 313 }; 314 } 315 316 Level findLevel(Evaluator evaluator, String s) { 317 Cube cube = evaluator.getCube(); 318 OlapElement o = (s.startsWith("[")) ? 319 evaluator.getSchemaReader().lookupCompound( 320 cube, 321 parseIdentifier(s), 322 false, 323 Category.Level) : 324 // lookupCompound barfs if "s" doesn't have matching 325 // brackets, so don't even try 326 null; 327 328 if (o instanceof Level) { 329 return (Level) o; 330 } else if (o == null) { 331 throw newEvalException(this, "Level '" + s + "' not found"); 332 } else { 333 throw newEvalException(this, "Levels('" + s + "') found " + o); 334 } 335 } 336 }); 337 338 // 339 // LOGICAL FUNCTIONS 340 define(IsEmptyFunDef.FunctionResolver); 341 define(IsEmptyFunDef.PostfixResolver); 342 define(IsNullFunDef.Resolver); 343 define(IsFunDef.Resolver); 344 345 // 346 // MEMBER FUNCTIONS 347 define(AncestorFunDef.Resolver); 348 349 define(new FunDefBase( 350 "Cousin", 351 "<Member> Cousin(<Member>, <Ancestor Member>)", 352 "Returns the member with the same relative position under <ancestor member> as the member specified.", 353 "fmmm") { 354 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 355 final MemberCalc memberCalc = 356 compiler.compileMember(call.getArg(0)); 357 final MemberCalc ancestorMemberCalc = 358 compiler.compileMember(call.getArg(1)); 359 return new AbstractMemberCalc(call, new Calc[] {memberCalc, ancestorMemberCalc}) { 360 public Member evaluateMember(Evaluator evaluator) { 361 Member member = memberCalc.evaluateMember(evaluator); 362 Member ancestorMember = ancestorMemberCalc.evaluateMember(evaluator); 363 return cousin( 364 evaluator.getSchemaReader(), 365 member, 366 ancestorMember); 367 } 368 }; 369 } 370 371 }); 372 373 define(DimensionCurrentMemberFunDef.instance); 374 375 define(HierarchyCurrentMemberFunDef.instance); 376 377 // "<Member>.DataMember" 378 define(new FunDefBase( 379 "DataMember", 380 "Returns the system-generated data member that is associated with a nonleaf member of a dimension.", 381 "pmm") { 382 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 383 final MemberCalc memberCalc = 384 compiler.compileMember(call.getArg(0)); 385 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 386 public Member evaluateMember(Evaluator evaluator) { 387 Member member = memberCalc.evaluateMember(evaluator); 388 return member.getDataMember(); 389 } 390 }; 391 } 392 393 }); 394 395 // "<Dimension>.DefaultMember" 396 define(new FunDefBase( 397 "DefaultMember", 398 "Returns the default member of a dimension.", 399 "pmd") { 400 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 401 final DimensionCalc dimensionCalc = 402 compiler.compileDimension(call.getArg(0)); 403 return new AbstractMemberCalc(call, new Calc[] {dimensionCalc}) { 404 public Member evaluateMember(Evaluator evaluator) { 405 Dimension dimension = 406 dimensionCalc.evaluateDimension(evaluator); 407 return evaluator.getSchemaReader() 408 .getHierarchyDefaultMember( 409 dimension.getHierarchies()[0]); 410 } 411 }; 412 } 413 }); 414 415 // "<Hierarchy>.DefaultMember" 416 define(new FunDefBase( 417 "DefaultMember", 418 "Returns the default member of a hierarchy.", 419 "pmh") { 420 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 421 final HierarchyCalc hierarchyCalc = 422 compiler.compileHierarchy(call.getArg(0)); 423 return new AbstractMemberCalc(call, new Calc[] {hierarchyCalc}) { 424 public Member evaluateMember(Evaluator evaluator) { 425 Hierarchy hierarchy = 426 hierarchyCalc.evaluateHierarchy(evaluator); 427 return evaluator.getSchemaReader() 428 .getHierarchyDefaultMember(hierarchy); 429 } 430 }; 431 } 432 }); 433 434 // "<Member>.FirstChild" 435 define(new FunDefBase( 436 "FirstChild", 437 "Returns the first child of a member.", 438 "pmm") { 439 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 440 final MemberCalc memberCalc = 441 compiler.compileMember(call.getArg(0)); 442 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 443 public Member evaluateMember(Evaluator evaluator) { 444 Member member = memberCalc.evaluateMember(evaluator); 445 return firstChild(evaluator, member); 446 } 447 }; 448 } 449 450 Member firstChild(Evaluator evaluator, Member member) { 451 List<Member> children = evaluator.getSchemaReader() 452 .getMemberChildren(member); 453 return (children.size() == 0) 454 ? member.getHierarchy().getNullMember() 455 : children.get(0); 456 } 457 }); 458 459 // <Member>.FirstSibling 460 define(new FunDefBase( 461 "FirstSibling", 462 "Returns the first child of the parent of a member.", 463 "pmm") { 464 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 465 final MemberCalc memberCalc = 466 compiler.compileMember(call.getArg(0)); 467 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 468 public Member evaluateMember(Evaluator evaluator) { 469 Member member = memberCalc.evaluateMember(evaluator); 470 return firstSibling(member, evaluator); 471 } 472 }; 473 } 474 475 Member firstSibling(Member member, Evaluator evaluator) { 476 Member parent = member.getParentMember(); 477 List<Member> children; 478 final SchemaReader schemaReader = evaluator.getSchemaReader(); 479 if (parent == null) { 480 if (member.isNull()) { 481 return member; 482 } 483 children = schemaReader.getHierarchyRootMembers( 484 member.getHierarchy()); 485 } else { 486 children = schemaReader.getMemberChildren(parent); 487 } 488 return children.get(0); 489 } 490 }); 491 492 define(LeadLagFunDef.LagResolver); 493 494 // <Member>.LastChild 495 define(new FunDefBase( 496 "LastChild", 497 "Returns the last child of a member.", 498 "pmm") { 499 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 500 final MemberCalc memberCalc = 501 compiler.compileMember(call.getArg(0)); 502 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 503 public Member evaluateMember(Evaluator evaluator) { 504 Member member = memberCalc.evaluateMember(evaluator); 505 return lastChild(evaluator, member); 506 } 507 }; 508 } 509 510 Member lastChild(Evaluator evaluator, Member member) { 511 List<Member> children = 512 evaluator.getSchemaReader().getMemberChildren(member); 513 return (children.size() == 0) 514 ? member.getHierarchy().getNullMember() 515 : children.get(children.size() - 1); 516 } 517 }); 518 519 // <Member>.LastSibling 520 define(new FunDefBase( 521 "LastSibling", 522 "Returns the last child of the parent of a member.", 523 "pmm") { 524 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 525 final MemberCalc memberCalc = 526 compiler.compileMember(call.getArg(0)); 527 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 528 public Member evaluateMember(Evaluator evaluator) { 529 Member member = memberCalc.evaluateMember(evaluator); 530 return firstSibling(member, evaluator); 531 } 532 }; 533 } 534 535 Member firstSibling(Member member, Evaluator evaluator) { 536 Member parent = member.getParentMember(); 537 List<Member> children; 538 final SchemaReader schemaReader = evaluator.getSchemaReader(); 539 if (parent == null) { 540 if (member.isNull()) { 541 return member; 542 } 543 children = schemaReader.getHierarchyRootMembers( 544 member.getHierarchy()); 545 } else { 546 children = schemaReader.getMemberChildren(parent); 547 } 548 return children.get(children.size() - 1); 549 } 550 }); 551 552 define(LeadLagFunDef.LeadResolver); 553 554 // Members(<String Expression>) 555 define(new FunDefBase( 556 "Members", 557 "Returns the member whose name is specified by a string expression.", 558 "fmS") { 559 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 560 throw new UnsupportedOperationException(); 561 } 562 }); 563 564 // <Member>.NextMember 565 define(new FunDefBase( 566 "NextMember", 567 "Returns the next member in the level that contains a specified member.", 568 "pmm") { 569 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 570 final MemberCalc memberCalc = 571 compiler.compileMember(call.getArg(0)); 572 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 573 public Member evaluateMember(Evaluator evaluator) { 574 Member member = memberCalc.evaluateMember(evaluator); 575 return evaluator.getSchemaReader().getLeadMember(member, +1); 576 } 577 }; 578 } 579 580 }); 581 582 define(OpeningClosingPeriodFunDef.OpeningPeriodResolver); 583 define(OpeningClosingPeriodFunDef.ClosingPeriodResolver); 584 585 define(ParallelPeriodFunDef.Resolver); 586 587 // <Member>.Parent 588 define(new FunDefBase( 589 "Parent", 590 "Returns the parent of a member.", 591 "pmm") { 592 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 593 final MemberCalc memberCalc = 594 compiler.compileMember(call.getArg(0)); 595 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 596 public Member evaluateMember(Evaluator evaluator) { 597 Member member = memberCalc.evaluateMember(evaluator); 598 return memberParent(evaluator, member); 599 } 600 }; 601 } 602 603 Member memberParent(Evaluator evaluator, Member member) { 604 Member parent = evaluator.getSchemaReader().getMemberParent(member); 605 if (parent == null) { 606 parent = member.getHierarchy().getNullMember(); 607 } 608 return parent; 609 } 610 611 }); 612 613 // <Member>.PrevMember 614 define(new FunDefBase( 615 "PrevMember", 616 "Returns the previous member in the level that contains a specified member.", 617 "pmm") { 618 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 619 final MemberCalc memberCalc = 620 compiler.compileMember(call.getArg(0)); 621 return new AbstractMemberCalc(call, new Calc[] {memberCalc}) { 622 public Member evaluateMember(Evaluator evaluator) { 623 Member member = memberCalc.evaluateMember(evaluator); 624 return evaluator.getSchemaReader().getLeadMember(member, -1); 625 } 626 }; 627 } 628 }); 629 630 // StrToMember(<String Expression>) 631 define(new FunDefBase( 632 "StrToMember", 633 "Returns a member from a unique name String in MDX format.", 634 "fmS") { 635 public Calc compileCall(ResolvedFunCall call,ExpCompiler compiler) { 636 final StringCalc memberNameCalc = 637 compiler.compileString(call.getArg(0)); 638 return new AbstractMemberCalc(call,new Calc[]{memberNameCalc}) { 639 public Member evaluateMember(Evaluator evaluator) { 640 String memberName = 641 memberNameCalc.evaluateString(evaluator); 642 return strToMember(evaluator, memberName); 643 } 644 }; 645 } 646 647 Member strToMember(Evaluator evaluator, String memberName) { 648 Cube cube = evaluator.getCube(); 649 SchemaReader schemaReader = evaluator.getSchemaReader(); 650 List<Id.Segment> uniqueNameParts = 651 Util.parseIdentifier(memberName); 652 return (Member) schemaReader.lookupCompound( 653 cube, uniqueNameParts, true, Category.Member); 654 } 655 }); 656 657 define(ValidMeasureFunDef.instance); 658 659 // 660 // NUMERIC FUNCTIONS 661 define(AggregateFunDef.resolver); 662 663 // Obsolete?? 664 define(new MultiResolver( 665 "$AggregateChildren", 666 "$AggregateChildren(<Hierarchy>)", 667 "Equivalent to 'Aggregate(<Hierarchy>.CurrentMember.Children); for internal use.", 668 new String[] {"Inh"}) { 669 protected FunDef createFunDef(Exp[] args, FunDef dummyFunDef) { 670 return new FunDefBase(dummyFunDef) { 671 public void unparse(Exp[] args, PrintWriter pw) { 672 pw.print(getName()); 673 pw.print("("); 674 args[0].unparse(pw); 675 pw.print(")"); 676 } 677 678 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 679 final HierarchyCalc hierarchyCalc = 680 compiler.compileHierarchy(call.getArg(0)); 681 final Calc valueCalc = new ValueCalc(call); 682 return new GenericCalc(call) { 683 public Object evaluate(Evaluator evaluator) { 684 Hierarchy hierarchy = 685 hierarchyCalc.evaluateHierarchy(evaluator); 686 return aggregateChildren(evaluator, hierarchy, valueCalc); 687 } 688 689 public Calc[] getCalcs() { 690 return new Calc[] {hierarchyCalc, valueCalc}; 691 } 692 }; 693 } 694 695 Object aggregateChildren( 696 Evaluator evaluator, Hierarchy hierarchy, final Calc valueFunCall) { 697 Member member = evaluator.getParent().getContext(hierarchy.getDimension()); 698 List members = 699 (List) member.getPropertyValue( 700 Property.CONTRIBUTING_CHILDREN.name); 701 Aggregator aggregator = 702 (Aggregator) evaluator.getProperty( 703 Property.AGGREGATION_TYPE.name, null); 704 if (aggregator == null) { 705 throw FunUtil.newEvalException(null, "Could not find an aggregator in the current evaluation context"); 706 } 707 Aggregator rollup = aggregator.getRollup(); 708 if (rollup == null) { 709 throw FunUtil.newEvalException(null, "Don't know how to rollup aggregator '" + aggregator + "'"); 710 } 711 return rollup.aggregate(evaluator.push(), members, valueFunCall); 712 } 713 }; 714 } 715 }); 716 717 define(AvgFunDef.Resolver); 718 719 define(CorrelationFunDef.Resolver); 720 721 define(CountFunDef.Resolver); 722 723 // <Set>.Count 724 define(new FunDefBase( 725 "Count", 726 "Returns the number of tuples in a set including empty cells.", 727 "pnx") { 728 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 729 final ListCalc memberListCalc = 730 compiler.compileList(call.getArg(0)); 731 return new AbstractIntegerCalc(call, new Calc[] {memberListCalc}) { 732 public int evaluateInteger(Evaluator evaluator) { 733 List memberList = 734 memberListCalc.evaluateList(evaluator); 735 return count(evaluator, memberList, true); 736 } 737 }; 738 } 739 }); 740 741 define(CovarianceFunDef.CovarianceResolver); 742 define(CovarianceFunDef.CovarianceNResolver); 743 744 define(IifFunDef.STRING_INSTANCE); 745 define(IifFunDef.NUMERIC_INSTANCE); 746 define(IifFunDef.TUPLE_INSTANCE); 747 define(IifFunDef.BOOLEAN_INSTANCE); 748 define(IifFunDef.MEMBER_INSTANCE); 749 define(IifFunDef.LEVEL_INSTANCE); 750 define(IifFunDef.HIERARCHY_INSTANCE); 751 define(IifFunDef.DIMENSION_INSTANCE); 752 define(IifFunDef.SET_INSTANCE); 753 754 // InStr(<String Expression>, <String Expression>) 755 define(new FunDefBase( 756 "InStr", 757 "Returns the position of the first occurrence of one string within another." + 758 " Implements very basic form of InStr", 759 "fnSS") { 760 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 761 final StringCalc stringCalc1 = compiler.compileString(call.getArg(0)); 762 final StringCalc stringCalc2 = compiler.compileString(call.getArg(1)); 763 return new AbstractIntegerCalc(call, new Calc[] {stringCalc1, stringCalc2}) { 764 public int evaluateInteger(Evaluator evaluator) { 765 String value = stringCalc1.evaluateString(evaluator); 766 String pattern = stringCalc2.evaluateString(evaluator); 767 return value.indexOf(pattern) + 1; 768 } 769 }; 770 } 771 }); 772 773 define(LinReg.InterceptResolver); 774 define(LinReg.PointResolver); 775 define(LinReg.R2Resolver); 776 define(LinReg.SlopeResolver); 777 define(LinReg.VarianceResolver); 778 779 define(MinMaxFunDef.MaxResolver); 780 define(MinMaxFunDef.MinResolver); 781 782 define(MedianFunDef.Resolver); 783 define(PercentileFunDef.Resolver); 784 785 // <Level>.Ordinal 786 define(new FunDefBase( 787 "Ordinal", 788 "Returns the zero-based ordinal value associated with a level.", 789 "pnl") { 790 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 791 final LevelCalc levelCalc = 792 compiler.compileLevel(call.getArg(0)); 793 return new AbstractIntegerCalc(call, new Calc[] {levelCalc}) { 794 public int evaluateInteger(Evaluator evaluator) { 795 final Level level = levelCalc.evaluateLevel(evaluator); 796 return level.getDepth(); 797 } 798 }; 799 } 800 801 }); 802 803 define(RankFunDef.Resolver); 804 805 define(CacheFunDef.Resolver); 806 807 define(StdevFunDef.StdevResolver); 808 define(StdevFunDef.StddevResolver); 809 810 define(StdevPFunDef.StdevpResolver); 811 define(StdevPFunDef.StddevpResolver); 812 813 define(SumFunDef.Resolver); 814 815 // <Measure>.Value 816 define(new FunDefBase( 817 "Value", 818 "Returns the value of a measure.", 819 "pnm") { 820 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 821 final MemberCalc memberCalc = 822 compiler.compileMember(call.getArg(0)); 823 return new GenericCalc(call) { 824 public Object evaluate(Evaluator evaluator) { 825 Member member = memberCalc.evaluateMember(evaluator); 826 Member old = evaluator.setContext(member); 827 Object value = evaluator.evaluateCurrent(); 828 evaluator.setContext(old); 829 return value; 830 } 831 832 public boolean dependsOn(Dimension dimension) { 833 if (super.dependsOn(dimension)) { 834 return true; 835 } 836 if (memberCalc.getType().usesDimension(dimension, true)) { 837 return false; 838 } 839 return true; 840 } 841 public Calc[] getCalcs() { 842 return new Calc[] {memberCalc}; 843 } 844 }; 845 } 846 847 }); 848 849 define(VarFunDef.VarResolver); 850 define(VarFunDef.VarianceResolver); 851 852 define(VarPFunDef.VariancePResolver); 853 define(VarPFunDef.VarPResolver); 854 855 // 856 // SET FUNCTIONS 857 858 define(AddCalculatedMembersFunDef.resolver); 859 860 // Ascendants(<Member>) 861 define(new FunDefBase( 862 "Ascendants", 863 "Returns the set of the ascendants of a specified member.", 864 "fxm") { 865 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 866 final MemberCalc memberCalc = 867 compiler.compileMember(call.getArg(0)); 868 return new AbstractListCalc(call, new Calc[] {memberCalc}) { 869 public List evaluateList(Evaluator evaluator) { 870 Member member = memberCalc.evaluateMember(evaluator); 871 return ascendants(member); 872 } 873 }; 874 } 875 876 List<Member> ascendants(Member member) { 877 if (member.isNull()) { 878 return Collections.emptyList(); 879 } 880 List<Member> members = member.getAncestorMembers(); 881 final List<Member> result = 882 new ArrayList<Member>(members.size() + 1); 883 result.add(member); 884 result.addAll(members); 885 return result; 886 } 887 }); 888 889 define(TopBottomCountFunDef.BottomCountResolver); 890 define(TopBottomPercentSumFunDef.BottomPercentResolver); 891 define(TopBottomPercentSumFunDef.BottomSumResolver); 892 define(TopBottomCountFunDef.TopCountResolver); 893 define(TopBottomPercentSumFunDef.TopPercentResolver); 894 define(TopBottomPercentSumFunDef.TopSumResolver); 895 896 // <Member>.Children 897 define(new FunDefBase( 898 "Children", 899 "Returns the children of a member.", 900 "pxm") { 901 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 902 final MemberCalc memberCalc = 903 compiler.compileMember(call.getArg(0)); 904 return new AbstractListCalc(call, new Calc[] {memberCalc}, false) { 905 public List evaluateList(Evaluator evaluator) { 906 // Return the list of children. The list is immutable, 907 // hence 'false' above. 908 Member member = memberCalc.evaluateMember(evaluator); 909 return getNonEmptyMemberChildren(evaluator, member); 910 } 911 }; 912 } 913 914 }); 915 916 define(CrossJoinFunDef.Resolver); 917 define(NonEmptyCrossJoinFunDef.Resolver); 918 define(CrossJoinFunDef.StarResolver); 919 define(DescendantsFunDef.Resolver); 920 define(DistinctFunDef.instance); 921 define(DrilldownLevelFunDef.Resolver); 922 923 define(DrilldownLevelTopBottomFunDef.DrilldownLevelTopResolver); 924 define(DrilldownLevelTopBottomFunDef.DrilldownLevelBottomResolver); 925 define(DrilldownMemberFunDef.Resolver); 926 927 if (false) define(new FunDefBase( 928 "DrilldownMemberBottom", 929 "DrilldownMemberBottom(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", 930 "Like DrilldownMember except that it includes only the bottom N children.", 931 "fx*") { 932 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 933 throw new UnsupportedOperationException(); 934 } 935 }); 936 937 if (false) define(new FunDefBase( 938 "DrilldownMemberTop", 939 "DrilldownMemberTop(<Set1>, <Set2>, <Count>[, [<Numeric Expression>][, RECURSIVE]])", 940 "Like DrilldownMember except that it includes only the top N children.", 941 "fx*") { 942 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 943 throw new UnsupportedOperationException(); 944 } 945 }); 946 947 if (false) define(new FunDefBase( 948 "DrillupLevel", 949 "DrillupLevel(<Set>[, <Level>])", 950 "Drills up the members of a set that are below a specified level.", 951 "fx*") { 952 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 953 throw new UnsupportedOperationException(); 954 } 955 }); 956 957 if (false) define(new FunDefBase( 958 "DrillupMember", 959 "DrillupMember(<Set1>, <Set2>)", 960 "Drills up the members in a set that are present in a second specified set.", 961 "fx*") { 962 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 963 throw new UnsupportedOperationException(); 964 } 965 }); 966 967 define(ExceptFunDef.Resolver); 968 define(ExistsFunDef.resolver); 969 define(ExtractFunDef.Resolver); 970 define(FilterFunDef.instance); 971 972 define(GenerateFunDef.ListResolver); 973 define(GenerateFunDef.StringResolver); 974 define(HeadTailFunDef.HeadResolver); 975 976 define(HierarchizeFunDef.Resolver); 977 978 define(IntersectFunDef.resolver); 979 define(LastPeriodsFunDef.Resolver); 980 981 // <Dimension>.Members 982 define(new FunDefBase( 983 "Members", 984 "Returns the set of members in a dimension.", 985 "pxd") { 986 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 987 final DimensionCalc dimensionCalc = 988 compiler.compileDimension(call.getArg(0)); 989 return new AbstractListCalc(call, new Calc[] {dimensionCalc}) { 990 public List evaluateList(Evaluator evaluator) { 991 Dimension dimension = 992 dimensionCalc.evaluateDimension(evaluator); 993 return dimensionMembers(dimension, evaluator, false); 994 } 995 }; 996 } 997 998 }); 999 1000 // <Dimension>.AllMembers 1001 define(new FunDefBase( 1002 "AllMembers", 1003 "Returns a set that contains all members, including calculated members, of the specified dimension.", 1004 "pxd") { 1005 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1006 final DimensionCalc dimensionCalc = 1007 compiler.compileDimension(call.getArg(0)); 1008 return new AbstractListCalc(call, new Calc[] {dimensionCalc}) { 1009 public List evaluateList(Evaluator evaluator) { 1010 Dimension dimension = 1011 dimensionCalc.evaluateDimension(evaluator); 1012 return dimensionMembers(dimension, evaluator, true); 1013 } 1014 }; 1015 } 1016 1017 }); 1018 1019 // <Hierarchy>.Members 1020 define(new FunDefBase( 1021 "Members", 1022 "Returns the set of members in a hierarchy.", 1023 "pxh") { 1024 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1025 final HierarchyCalc hierarchyCalc = 1026 compiler.compileHierarchy(call.getArg(0)); 1027 return new AbstractListCalc(call, new Calc[] {hierarchyCalc}) { 1028 public List evaluateList(Evaluator evaluator) { 1029 Hierarchy hierarchy = 1030 hierarchyCalc.evaluateHierarchy(evaluator); 1031 return hierarchyMembers(hierarchy, evaluator, false); 1032 } 1033 }; 1034 } 1035 1036 }); 1037 1038 // <Hierarchy>.AllMembers 1039 define(new FunDefBase( 1040 "AllMembers", 1041 "Returns a set that contains all members, including calculated members, of the specified hierarchy.", 1042 "pxh") { 1043 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1044 final HierarchyCalc hierarchyCalc = 1045 compiler.compileHierarchy(call.getArg(0)); 1046 return new AbstractListCalc(call, new Calc[] {hierarchyCalc}) { 1047 public List evaluateList(Evaluator evaluator) { 1048 Hierarchy hierarchy = 1049 hierarchyCalc.evaluateHierarchy(evaluator); 1050 return hierarchyMembers(hierarchy, evaluator, true); 1051 } 1052 }; 1053 } 1054 }); 1055 1056 // <Level>.Members 1057 define(new FunDefBase( 1058 "Members", 1059 "Returns the set of members in a level.", 1060 "pxl") { 1061 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1062 final LevelCalc levelCalc = 1063 compiler.compileLevel(call.getArg(0)); 1064 return new AbstractMemberListCalc(call, new Calc[] {levelCalc}) { 1065 public List<Member> evaluateMemberList(Evaluator evaluator) { 1066 Level level = levelCalc.evaluateLevel(evaluator); 1067 return levelMembers(level, evaluator, false); 1068 } 1069 }; 1070 } 1071 }); 1072 1073 // <Level>.AllMembers 1074 define(new FunDefBase( 1075 "AllMembers", 1076 "Returns a set that contains all members, including calculated members, of the specified level.", 1077 "pxl") { 1078 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1079 final LevelCalc levelCalc = 1080 compiler.compileLevel(call.getArg(0)); 1081 return new AbstractMemberListCalc(call, new Calc[] {levelCalc}) { 1082 public List<Member> evaluateMemberList(Evaluator evaluator) { 1083 Level level = levelCalc.evaluateLevel(evaluator); 1084 return levelMembers(level, evaluator, true); 1085 } 1086 }; 1087 } 1088 }); 1089 1090 define(XtdFunDef.MtdResolver); 1091 define(OrderFunDef.Resolver); 1092 define(UnorderFunDef.Resolver); 1093 define(PeriodsToDateFunDef.Resolver); 1094 define(XtdFunDef.QtdResolver); 1095 1096 // StripCalculatedMembers(<Set>) 1097 define(new FunDefBase( 1098 "StripCalculatedMembers", 1099 "Removes calculated members from a set.", 1100 "fxx") { 1101 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1102 final ListCalc listCalc = 1103 compiler.compileList(call.getArg(0)); 1104 return new AbstractListCalc(call, new Calc[] {listCalc}) { 1105 public List evaluateList(Evaluator evaluator) { 1106 List<Member> list = listCalc.evaluateList(evaluator); 1107 list = removeCalculatedMembers(list); 1108 return list; 1109 } 1110 }; 1111 } 1112 1113 }); 1114 1115 // <Member>.Siblings 1116 define(new FunDefBase( 1117 "Siblings", 1118 "Returns the siblings of a specified member, including the member itself.", 1119 "pxm") { 1120 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1121 final MemberCalc memberCalc = 1122 compiler.compileMember(call.getArg(0)); 1123 return new AbstractListCalc(call, new Calc[] {memberCalc}) { 1124 public List evaluateList(Evaluator evaluator) { 1125 final Member member = 1126 memberCalc.evaluateMember(evaluator); 1127 return memberSiblings(member, evaluator); 1128 } 1129 }; 1130 } 1131 1132 List memberSiblings(Member member, Evaluator evaluator) { 1133 if (member.isNull()) { 1134 // the null member has no siblings -- not even itself 1135 return Collections.EMPTY_LIST; 1136 } 1137 Member parent = member.getParentMember(); 1138 final SchemaReader schemaReader = evaluator.getSchemaReader(); 1139 if (parent == null) { 1140 return schemaReader.getHierarchyRootMembers( 1141 member.getHierarchy()); 1142 } else { 1143 return schemaReader.getMemberChildren(parent); 1144 } 1145 } 1146 }); 1147 1148 define(StrToSetFunDef.Resolver); 1149 define(SubsetFunDef.Resolver); 1150 define(HeadTailFunDef.TailResolver); 1151 define(ToggleDrillStateFunDef.Resolver); 1152 define(UnionFunDef.Resolver); 1153 define(VisualTotalsFunDef.Resolver); 1154 define(XtdFunDef.WtdResolver); 1155 define(XtdFunDef.YtdResolver); 1156 define(RangeFunDef.instance); // "<member> : <member>" operator 1157 define(SetFunDef.Resolver); // "{ <member> [,...] }" operator 1158 1159 // 1160 // STRING FUNCTIONS 1161 define(FormatFunDef.Resolver); 1162 1163 // <Dimension>.Caption 1164 define(new FunDefBase( 1165 "Caption", 1166 "Returns the caption of a dimension.", 1167 "pSd") { 1168 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1169 final DimensionCalc dimensionCalc = 1170 compiler.compileDimension(call.getArg(0)); 1171 return new AbstractStringCalc(call, new Calc[] {dimensionCalc}) { 1172 public String evaluateString(Evaluator evaluator) { 1173 final Dimension dimension = 1174 dimensionCalc.evaluateDimension(evaluator); 1175 return dimension.getCaption(); 1176 } 1177 }; 1178 } 1179 }); 1180 1181 // <Hierarchy>.Caption 1182 define(new FunDefBase( 1183 "Caption", 1184 "Returns the caption of a hierarchy.", 1185 "pSh") { 1186 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1187 final HierarchyCalc hierarchyCalc = 1188 compiler.compileHierarchy(call.getArg(0)); 1189 return new AbstractStringCalc(call, new Calc[] {hierarchyCalc}) { 1190 public String evaluateString(Evaluator evaluator) { 1191 final Hierarchy hierarchy = 1192 hierarchyCalc.evaluateHierarchy(evaluator); 1193 return hierarchy.getCaption(); 1194 } 1195 }; 1196 } 1197 1198 }); 1199 1200 // <Level>.Caption 1201 define(new FunDefBase( 1202 "Caption", 1203 "Returns the caption of a level.", 1204 "pSl") { 1205 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1206 final LevelCalc levelCalc = 1207 compiler.compileLevel(call.getArg(0)); 1208 return new AbstractStringCalc(call, new Calc[] {levelCalc}) { 1209 public String evaluateString(Evaluator evaluator) { 1210 final Level level = levelCalc.evaluateLevel(evaluator); 1211 return level.getCaption(); 1212 } 1213 }; 1214 } 1215 }); 1216 1217 // <Member>.Caption 1218 define(new FunDefBase( 1219 "Caption", 1220 "Returns the caption of a member.", 1221 "pSm") { 1222 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1223 final MemberCalc memberCalc = 1224 compiler.compileMember(call.getArg(0)); 1225 return new AbstractStringCalc(call, new Calc[] {memberCalc}) { 1226 public String evaluateString(Evaluator evaluator) { 1227 final Member member = 1228 memberCalc.evaluateMember(evaluator); 1229 return member.getCaption(); 1230 } 1231 }; 1232 } 1233 }); 1234 1235 // <Dimension>.Name 1236 define(new FunDefBase( 1237 "Name", 1238 "Returns the name of a dimension.", 1239 "pSd") { 1240 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1241 final DimensionCalc dimensionCalc = 1242 compiler.compileDimension(call.getArg(0)); 1243 return new AbstractStringCalc(call, new Calc[] {dimensionCalc}) { 1244 public String evaluateString(Evaluator evaluator) { 1245 final Dimension dimension = 1246 dimensionCalc.evaluateDimension(evaluator); 1247 return dimension.getName(); 1248 } 1249 }; 1250 } 1251 }); 1252 1253 // <Hierarchy>.Name 1254 define(new FunDefBase( 1255 "Name", 1256 "Returns the name of a hierarchy.", 1257 "pSh") { 1258 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1259 final HierarchyCalc hierarchyCalc = 1260 compiler.compileHierarchy(call.getArg(0)); 1261 return new AbstractStringCalc(call, new Calc[] {hierarchyCalc}) { 1262 public String evaluateString(Evaluator evaluator) { 1263 final Hierarchy hierarchy = 1264 hierarchyCalc.evaluateHierarchy(evaluator); 1265 return hierarchy.getName(); 1266 } 1267 }; 1268 } 1269 }); 1270 1271 // <Level>.Name 1272 define(new FunDefBase( 1273 "Name", 1274 "Returns the name of a level.", 1275 "pSl") { 1276 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1277 final LevelCalc levelCalc = 1278 compiler.compileLevel(call.getArg(0)); 1279 return new AbstractStringCalc(call, new Calc[] {levelCalc}) { 1280 public String evaluateString(Evaluator evaluator) { 1281 final Level level = levelCalc.evaluateLevel(evaluator); 1282 return level.getName(); 1283 } 1284 }; 1285 } 1286 }); 1287 1288 // <Member>.Name 1289 define(new FunDefBase( 1290 "Name", 1291 "Returns the name of a member.", 1292 "pSm") { 1293 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1294 final MemberCalc memberCalc = 1295 compiler.compileMember(call.getArg(0)); 1296 return new AbstractStringCalc(call, new Calc[] {memberCalc}) { 1297 public String evaluateString(Evaluator evaluator) { 1298 final Member member = 1299 memberCalc.evaluateMember(evaluator); 1300 return member.getName(); 1301 } 1302 }; 1303 } 1304 }); 1305 1306 define(SetToStrFunDef.instance); 1307 1308 define(TupleToStrFunDef.instance); 1309 1310 // <Dimension>.UniqueName 1311 define(new FunDefBase( 1312 "UniqueName", 1313 "Returns the unique name of a dimension.", 1314 "pSd") { 1315 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1316 final DimensionCalc dimensionCalc = 1317 compiler.compileDimension(call.getArg(0)); 1318 return new AbstractStringCalc(call, new Calc[] {dimensionCalc}) { 1319 public String evaluateString(Evaluator evaluator) { 1320 final Dimension dimension = 1321 dimensionCalc.evaluateDimension(evaluator); 1322 return dimension.getUniqueName(); 1323 } 1324 }; 1325 } 1326 }); 1327 1328 // <Hierarchy>.UniqueName 1329 define(new FunDefBase( 1330 "UniqueName", 1331 "Returns the unique name of a hierarchy.", 1332 "pSh") { 1333 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1334 final HierarchyCalc hierarchyCalc = 1335 compiler.compileHierarchy(call.getArg(0)); 1336 return new AbstractStringCalc(call, new Calc[] {hierarchyCalc}) { 1337 public String evaluateString(Evaluator evaluator) { 1338 final Hierarchy hierarchy = 1339 hierarchyCalc.evaluateHierarchy(evaluator); 1340 return hierarchy.getUniqueName(); 1341 } 1342 }; 1343 } 1344 }); 1345 1346 // <Level>.UniqueName 1347 define(new FunDefBase( 1348 "UniqueName", 1349 "Returns the unique name of a level.", 1350 "pSl") { 1351 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1352 final LevelCalc levelCalc = 1353 compiler.compileLevel(call.getArg(0)); 1354 return new AbstractStringCalc(call, new Calc[] {levelCalc}) { 1355 public String evaluateString(Evaluator evaluator) { 1356 final Level level = levelCalc.evaluateLevel(evaluator); 1357 return level.getUniqueName(); 1358 } 1359 }; 1360 } 1361 }); 1362 1363 // <Member>.UniqueName 1364 define(new FunDefBase( 1365 "UniqueName", 1366 "Returns the unique name of a member.", 1367 "pSm") { 1368 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1369 final MemberCalc memberCalc = 1370 compiler.compileMember(call.getArg(0)); 1371 return new AbstractStringCalc(call, new Calc[] {memberCalc}) { 1372 public String evaluateString(Evaluator evaluator) { 1373 final Member member = 1374 memberCalc.evaluateMember(evaluator); 1375 return member.getUniqueName(); 1376 } 1377 }; 1378 } 1379 }); 1380 1381 // 1382 // TUPLE FUNCTIONS 1383 1384 // <Set>.Current 1385 if (false) define(new FunDefBase( 1386 "Current", 1387 "Returns the current tuple from a set during an iteration.", 1388 "ptx") { 1389 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1390 throw new UnsupportedOperationException(); 1391 } 1392 }); 1393 1394 define(SetItemFunDef.intResolver); 1395 define(SetItemFunDef.stringResolver); 1396 define(TupleItemFunDef.instance); 1397 define(StrToTupleFunDef.Resolver); 1398 1399 // special resolver for "()" 1400 define(TupleFunDef.Resolver); 1401 1402 // 1403 // GENERIC VALUE FUNCTIONS 1404 define(CoalesceEmptyFunDef.Resolver); 1405 define(CaseTestFunDef.Resolver); 1406 define(CaseMatchFunDef.Resolver); 1407 define(PropertiesFunDef.Resolver); 1408 1409 // 1410 // PARAMETER FUNCTIONS 1411 define(new ParameterFunDef.ParameterResolver()); 1412 define(new ParameterFunDef.ParamRefResolver()); 1413 1414 // 1415 // OPERATORS 1416 1417 // <Numeric Expression> + <Numeric Expression> 1418 define(new FunDefBase( 1419 "+", 1420 "Adds two numbers.", 1421 "innn") { 1422 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1423 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1424 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1425 return new AbstractDoubleCalc(call, new Calc[] {calc0, calc1}) { 1426 public double evaluateDouble(Evaluator evaluator) { 1427 final double v0 = calc0.evaluateDouble(evaluator); 1428 final double v1 = calc1.evaluateDouble(evaluator); 1429 if (v0 == DoubleNull) { 1430 if (v1 == DoubleNull) { 1431 return DoubleNull; 1432 } else { 1433 return v1; 1434 } 1435 } else { 1436 if (v1 == DoubleNull) { 1437 return v0; 1438 } else { 1439 return v0 + v1; 1440 } 1441 } 1442 } 1443 }; 1444 } 1445 1446 }); 1447 1448 // <Numeric Expression> - <Numeric Expression> 1449 define(new FunDefBase( 1450 "-", 1451 "Subtracts two numbers.", 1452 "innn") { 1453 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1454 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1455 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1456 return new AbstractDoubleCalc(call, new Calc[] {calc0, calc1}) { 1457 public double evaluateDouble(Evaluator evaluator) { 1458 final double v0 = calc0.evaluateDouble(evaluator); 1459 final double v1 = calc1.evaluateDouble(evaluator); 1460 if (v0 == DoubleNull) { 1461 if (v1 == DoubleNull) { 1462 return DoubleNull; 1463 } else { 1464 return - v1; 1465 } 1466 } else { 1467 if (v1 == DoubleNull) { 1468 return v0; 1469 } else { 1470 return v0 - v1; 1471 } 1472 } 1473 } 1474 }; 1475 } 1476 }); 1477 1478 // <Numeric Expression> * <Numeric Expression> 1479 define(new FunDefBase( 1480 "*", 1481 "Multiplies two numbers.", 1482 "innn") { 1483 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1484 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1485 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1486 return new AbstractDoubleCalc(call, new Calc[] {calc0, calc1}) { 1487 public double evaluateDouble(Evaluator evaluator) { 1488 final double v0 = calc0.evaluateDouble(evaluator); 1489 final double v1 = calc1.evaluateDouble(evaluator); 1490 // Multiply and divide return null if EITHER arg is null. 1491 if (v0 == DoubleNull || v1 == DoubleNull) { 1492 return DoubleNull; 1493 } else { 1494 return v0 * v1; 1495 } 1496 } 1497 }; 1498 } 1499 }); 1500 1501 // <Numeric Expression> / <Numeric Expression> 1502 define(new FunDefBase( 1503 "/", 1504 "Divides two numbers.", 1505 "innn") { 1506 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1507 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1508 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1509 final boolean isNullDenominatorProducesNull = 1510 MondrianProperties.instance(). 1511 NullDenominatorProducesNull.get(); 1512 1513 // If the mondrian property 1514 // mondrian.olap.NullOrZeroDenominatorProducesNull 1515 // is false(default), Null in denominator with numeric numerator 1516 // returns infinity. This is consistent with MSAS. 1517 // 1518 // If this property is true, Null or zero in denominator returns 1519 // Null. This is only used by certain applications and does not 1520 // conform to MSAS behavior. 1521 if (isNullDenominatorProducesNull != true) { 1522 return new AbstractDoubleCalc(call, new Calc[] {calc0, calc1}) { 1523 public double evaluateDouble(Evaluator evaluator) { 1524 final double v0 = calc0.evaluateDouble(evaluator); 1525 final double v1 = calc1.evaluateDouble(evaluator); 1526 // Null in numerator always returns DoubleNull. 1527 // 1528 if (v0 == DoubleNull) { 1529 return DoubleNull; 1530 } else if (v1 == DoubleNull) { 1531 // Null only in denominator returns Infinity. 1532 return Double.POSITIVE_INFINITY; 1533 } else { 1534 return v0 / v1; 1535 } 1536 } 1537 }; 1538 } else { 1539 return new AbstractDoubleCalc(call, new Calc[] {calc0, calc1}) { 1540 public double evaluateDouble(Evaluator evaluator) { 1541 final double v0 = calc0.evaluateDouble(evaluator); 1542 final double v1 = calc1.evaluateDouble(evaluator); 1543 // Null in numerator or denominator returns DoubleNull. 1544 // 1545 if (v0 == DoubleNull || v1 == DoubleNull) { 1546 return DoubleNull; 1547 } else { 1548 return v0 / v1; 1549 } 1550 } 1551 }; 1552 } 1553 } 1554 }); 1555 1556 // - <Numeric Expression> 1557 define(new FunDefBase( 1558 "-", 1559 "Returns the negative of a number.", 1560 "Pnn") { 1561 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1562 final DoubleCalc calc = compiler.compileDouble(call.getArg(0)); 1563 return new AbstractDoubleCalc(call, new Calc[] {calc}) { 1564 public double evaluateDouble(Evaluator evaluator) { 1565 final double v = calc.evaluateDouble(evaluator); 1566 if (v == DoubleNull) { 1567 return DoubleNull; 1568 } else { 1569 return - v; 1570 } 1571 } 1572 }; 1573 } 1574 }); 1575 1576 // <String Expression> || <String Expression> 1577 define(new FunDefBase( 1578 "||", 1579 "Concatenates two strings.", 1580 "iSSS") { 1581 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1582 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1583 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1584 return new AbstractStringCalc(call, new Calc[] {calc0, calc1}) { 1585 public String evaluateString(Evaluator evaluator) { 1586 final String s0 = calc0.evaluateString(evaluator); 1587 final String s1 = calc1.evaluateString(evaluator); 1588 return s0 + s1; 1589 } 1590 }; 1591 } 1592 1593 }); 1594 1595 // <Logical Expression> AND <Logical Expression> 1596 define(new FunDefBase( 1597 "AND", 1598 "Returns the conjunction of two conditions.", 1599 "ibbb") { 1600 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1601 final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0)); 1602 final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1)); 1603 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1604 public boolean evaluateBoolean(Evaluator evaluator) { 1605 boolean b0 = calc0.evaluateBoolean(evaluator); 1606 // don't short-circuit evaluation if we're evaluating 1607 // the axes; that way, we can combine all measures 1608 // referenced in the AND expression in a single query 1609 if (!evaluator.isEvalAxes() && !b0) { 1610 return false; 1611 } 1612 boolean b1 = calc1.evaluateBoolean(evaluator); 1613 return b0 && b1; 1614 } 1615 }; 1616 } 1617 }); 1618 1619 // <Logical Expression> OR <Logical Expression> 1620 define(new FunDefBase( 1621 "OR", 1622 "Returns the disjunction of two conditions.", 1623 "ibbb") { 1624 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1625 final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0)); 1626 final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1)); 1627 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1628 public boolean evaluateBoolean(Evaluator evaluator) { 1629 boolean b0 = calc0.evaluateBoolean(evaluator); 1630 // don't short-circuit evaluation if we're evaluating 1631 // the axes; that way, we can combine all measures 1632 // referenced in the OR expression in a single query 1633 if (!evaluator.isEvalAxes() && b0) { 1634 return true; 1635 } 1636 boolean b1 = calc1.evaluateBoolean(evaluator); 1637 return b0 || b1; 1638 } 1639 }; 1640 } 1641 }); 1642 1643 // <Logical Expression> XOR <Logical Expression> 1644 define(new FunDefBase( 1645 "XOR", 1646 "Returns whether two conditions are mutually exclusive.", 1647 "ibbb") { 1648 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1649 final BooleanCalc calc0 = compiler.compileBoolean(call.getArg(0)); 1650 final BooleanCalc calc1 = compiler.compileBoolean(call.getArg(1)); 1651 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1652 public boolean evaluateBoolean(Evaluator evaluator) { 1653 final boolean b0 = calc0.evaluateBoolean(evaluator); 1654 final boolean b1 = calc1.evaluateBoolean(evaluator); 1655 return b0 != b1; 1656 } 1657 }; 1658 } 1659 }); 1660 1661 // NOT <Logical Expression> 1662 define(new FunDefBase( 1663 "NOT", 1664 "Returns the negation of a condition.", 1665 "Pbb") { 1666 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1667 final BooleanCalc calc = compiler.compileBoolean(call.getArg(0)); 1668 return new AbstractBooleanCalc(call, new Calc[] {calc}) { 1669 public boolean evaluateBoolean(Evaluator evaluator) { 1670 return !calc.evaluateBoolean(evaluator); 1671 } 1672 }; 1673 } 1674 }); 1675 1676 // <String Expression> = <String Expression> 1677 define(new FunDefBase( 1678 "=", 1679 "Returns whether two expressions are equal.", 1680 "ibSS") { 1681 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1682 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1683 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1684 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1685 public boolean evaluateBoolean(Evaluator evaluator) { 1686 final String b0 = calc0.evaluateString(evaluator); 1687 final String b1 = calc1.evaluateString(evaluator); 1688 if (b0 == null || b1 == null) { 1689 return BooleanNull; 1690 } 1691 return b0.equals(b1); 1692 } 1693 }; 1694 } 1695 }); 1696 1697 // <Numeric Expression> = <Numeric Expression> 1698 define(new FunDefBase( 1699 "=", 1700 "Returns whether two expressions are equal.", 1701 "ibnn") { 1702 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1703 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1704 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1705 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1706 public boolean evaluateBoolean(Evaluator evaluator) { 1707 final double v0 = calc0.evaluateDouble(evaluator); 1708 final double v1 = calc1.evaluateDouble(evaluator); 1709 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1710 return BooleanNull; 1711 } 1712 return v0 == v1; 1713 } 1714 }; 1715 } 1716 }); 1717 1718 // <String Expression> <> <String Expression> 1719 define(new FunDefBase( 1720 "<>", 1721 "Returns whether two expressions are not equal.", 1722 "ibSS") { 1723 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1724 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1725 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1726 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1727 public boolean evaluateBoolean(Evaluator evaluator) { 1728 final String b0 = calc0.evaluateString(evaluator); 1729 final String b1 = calc1.evaluateString(evaluator); 1730 if (b0 == null || b1 == null) { 1731 return BooleanNull; 1732 } 1733 return !b0.equals(b1); 1734 } 1735 }; 1736 } 1737 }); 1738 1739 // <Numeric Expression> <> <Numeric Expression> 1740 define(new FunDefBase( 1741 "<>", 1742 "Returns whether two expressions are not equal.", 1743 "ibnn") { 1744 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1745 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1746 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1747 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1748 public boolean evaluateBoolean(Evaluator evaluator) { 1749 final double v0 = calc0.evaluateDouble(evaluator); 1750 final double v1 = calc1.evaluateDouble(evaluator); 1751 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1752 return BooleanNull; 1753 } 1754 return v0 != v1; 1755 } 1756 }; 1757 } 1758 }); 1759 1760 // <Numeric Expression> < <Numeric Expression> 1761 define(new FunDefBase( 1762 "<", 1763 "Returns whether an expression is less than another.", 1764 "ibnn") { 1765 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1766 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1767 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1768 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1769 public boolean evaluateBoolean(Evaluator evaluator) { 1770 final double v0 = calc0.evaluateDouble(evaluator); 1771 final double v1 = calc1.evaluateDouble(evaluator); 1772 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1773 return BooleanNull; 1774 } 1775 return v0 < v1; 1776 } 1777 }; 1778 } 1779 }); 1780 1781 // <String Expression> < <String Expression> 1782 define(new FunDefBase( 1783 "<", 1784 "Returns whether an expression is less than another.", 1785 "ibSS") { 1786 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1787 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1788 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1789 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1790 public boolean evaluateBoolean(Evaluator evaluator) { 1791 final String b0 = calc0.evaluateString(evaluator); 1792 final String b1 = calc1.evaluateString(evaluator); 1793 if (b0 == null || b1 == null) { 1794 return BooleanNull; 1795 } 1796 return b0.compareTo(b1) < 0; 1797 } 1798 }; 1799 } 1800 }); 1801 1802 // <Numeric Expression> <= <Numeric Expression> 1803 define(new FunDefBase( 1804 "<=", 1805 "Returns whether an expression is less than or equal to another.", 1806 "ibnn") { 1807 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1808 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1809 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1810 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1811 public boolean evaluateBoolean(Evaluator evaluator) { 1812 final double v0 = calc0.evaluateDouble(evaluator); 1813 final double v1 = calc1.evaluateDouble(evaluator); 1814 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1815 return BooleanNull; 1816 } 1817 return v0 <= v1; 1818 } 1819 }; 1820 } 1821 }); 1822 1823 // <String Expression> <= <String Expression> 1824 define(new FunDefBase( 1825 "<=", 1826 "Returns whether an expression is less than or equal to another.", 1827 "ibSS") { 1828 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1829 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1830 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1831 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1832 public boolean evaluateBoolean(Evaluator evaluator) { 1833 final String b0 = calc0.evaluateString(evaluator); 1834 final String b1 = calc1.evaluateString(evaluator); 1835 if (b0 == null || b1 == null) { 1836 return BooleanNull; 1837 } 1838 return b0.compareTo(b1) <= 0; 1839 } 1840 }; 1841 } 1842 }); 1843 1844 // <Numeric Expression> > <Numeric Expression> 1845 define(new FunDefBase( 1846 ">", 1847 "Returns whether an expression is greater than another.", 1848 "ibnn") { 1849 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1850 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1851 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1852 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1853 public boolean evaluateBoolean(Evaluator evaluator) { 1854 final double v0 = calc0.evaluateDouble(evaluator); 1855 final double v1 = calc1.evaluateDouble(evaluator); 1856 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1857 return BooleanNull; 1858 } 1859 return v0 > v1; 1860 } 1861 }; 1862 } 1863 }); 1864 1865 // <String Expression> > <String Expression> 1866 define(new FunDefBase( 1867 ">", 1868 "Returns whether an expression is greater than another.", 1869 "ibSS") { 1870 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1871 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1872 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1873 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1874 public boolean evaluateBoolean(Evaluator evaluator) { 1875 final String b0 = calc0.evaluateString(evaluator); 1876 final String b1 = calc1.evaluateString(evaluator); 1877 if (b0 == null || b1 == null) { 1878 return BooleanNull; 1879 } 1880 return b0.compareTo(b1) > 0; 1881 } 1882 }; 1883 } 1884 }); 1885 1886 // <Numeric Expression> >= <Numeric Expression> 1887 define(new FunDefBase( 1888 ">=", 1889 "Returns whether an expression is greater than or equal to another.", 1890 "ibnn") { 1891 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1892 final DoubleCalc calc0 = compiler.compileDouble(call.getArg(0)); 1893 final DoubleCalc calc1 = compiler.compileDouble(call.getArg(1)); 1894 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1895 public boolean evaluateBoolean(Evaluator evaluator) { 1896 final double v0 = calc0.evaluateDouble(evaluator); 1897 final double v1 = calc1.evaluateDouble(evaluator); 1898 if (Double.isNaN(v0) || Double.isNaN(v1) || v0 == DoubleNull || v1 == DoubleNull) { 1899 return BooleanNull; 1900 } 1901 return v0 >= v1; 1902 } 1903 }; 1904 } 1905 }); 1906 1907 // <String Expression> >= <String Expression> 1908 define(new FunDefBase( 1909 ">=", 1910 "Returns whether an expression is greater than or equal to another.", 1911 "ibSS") { 1912 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1913 final StringCalc calc0 = compiler.compileString(call.getArg(0)); 1914 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 1915 return new AbstractBooleanCalc(call, new Calc[] {calc0, calc1}) { 1916 public boolean evaluateBoolean(Evaluator evaluator) { 1917 final String b0 = calc0.evaluateString(evaluator); 1918 final String b1 = calc1.evaluateString(evaluator); 1919 if (b0 == null || b1 == null) { 1920 return BooleanNull; 1921 } 1922 return b0.compareTo(b1) >= 0; 1923 } 1924 }; 1925 } 1926 }); 1927 1928 // NON-STANDARD FUNCTIONS 1929 1930 define(NthQuartileFunDef.FirstQResolver); 1931 1932 define(NthQuartileFunDef.ThirdQResolver); 1933 1934 define(CalculatedChildFunDef.instance); 1935 1936 define(CastFunDef.Resolver); 1937 1938 // UCase(<String Expression>) 1939 define(new FunDefBase( 1940 "UCase", 1941 "Returns a string that has been converted to uppercase", 1942 "fSS") { 1943 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1944 final Locale locale = compiler.getEvaluator().getConnectionLocale(); 1945 final StringCalc stringCalc = compiler.compileString(call.getArg(0)); 1946 return new AbstractStringCalc(call, new Calc[]{stringCalc}) { 1947 public String evaluateString(Evaluator evaluator) { 1948 String value = stringCalc.evaluateString(evaluator); 1949 return value.toUpperCase(locale); 1950 } 1951 }; 1952 } 1953 1954 }); 1955 1956 // Len(<String Expression>) 1957 define(new FunDefBase( 1958 "Len", 1959 "Returns the number of characters in a string", 1960 "fnS") { 1961 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 1962 final StringCalc stringCalc = compiler.compileString(call.getArg(0)); 1963 return new AbstractIntegerCalc(call, new Calc[] {stringCalc}) { 1964 public int evaluateInteger(Evaluator evaluator) { 1965 String value = stringCalc.evaluateString(evaluator); 1966 return value.length(); 1967 } 1968 }; 1969 } 1970 1971 }); 1972 1973 // Define VBA functions. 1974 for (FunDef funDef : JavaFunDef.scan(Vba.class)) { 1975 define(funDef); 1976 } 1977 1978 // Define Excel functions. 1979 for (FunDef funDef : JavaFunDef.scan(Excel.class)) { 1980 define(funDef); 1981 } 1982 } 1983 1984 /** 1985 * Returns the singleton, creating if necessary. 1986 * 1987 * @return the singleton 1988 */ 1989 public static BuiltinFunTable instance() { 1990 if (instance == null) { 1991 instance = new BuiltinFunTable(); 1992 instance.init(); 1993 } 1994 return instance; 1995 } 1996 } 1997 1998 // End BuiltinFunTable.java