    package flare.query
    {
        /**
         * Expression operator that performs function invocation. The set of
         * available functions is determined by a static function table maintained
         * by this class. The function table can be extended to introduce custom
         * functions into the query language.
         */
        public class Fn extends CompositeExpression
        {
            private var _name:String;
            private var _func:Function;
            private var _args:Array;

            /**
             * Creates a new Fn (function) operator.
             * @param name the name of the function. This should map to an entry
             *  in the static function table.
             * @params args sub-expressions for the function arguments
             */
            public function Fn(name:String, ...args) {
                _name = name.toUpperCase();
                _func = table[_name];
                super(args);
            }

            /**
             * @inheritDoc
             */
            public override function clone():Expression
            {
                return new Fn(_name, _children);
            }

            /**
             * @inheritDoc
             */
            public override function eval(o:Object=null):*
            {
                // first, initialize the argument array as needed
                if (_args == null || _args.length != _children.length) {
                    _args = new Array(_children.length);
                }
                // now evaluate all sub-expressions
                for (var i:int=0; i<_children.length; ++i) {
                    _args[i] = _children[i].eval(o);
                }
                // now evaluate the function
                return _func.apply(null, _args);
            }

            /**
             * @inheritDoc
             */
            public override function toString():String
            {
                return _name + getString();
            }

            // --------------------------------------------------------------------

            /**
             * Function table mapping function names to Function instances.
             * Functions can be added or removed at run-time by editing this
             * object.
             */
            public static var table:Object = {
                // Math Functions
                ABS:        Math.abs,
                ACOS:        Math.acos,
                ASIN:        Math.asin,
                ATAN:        Math.atan,
                ATAN2:        Math.atan2,
                CEIL:        Math.ceil,
                CEILING:    Math.ceil,
                COS:        Math.cos,
                EXP:        Math.exp,
                FLOOR:        Math.floor,
                LOG:        Math.log,
                MAX:        Math.max,
                MIN:        Math.min,
                POW:        Math.pow,
                POWER:        Math.pow,
                RANDOM:        Math.random,
                ROUND:        Math.round,
                SIN:        Math.sin,
                SQRT:        Math.sqrt,
                TAN:        Math.tan,

                // String Functions
                CONCAT:        StringUtil.concat,
                CONCAT_WS:    StringUtil.concat_ws,
                FORMAT:        StringUtil.format,
                INSERT:        StringUtil.insert,
                LEFT:        StringUtil.left,
                LENGTH:        StringUtil.length,
                LOWER:        StringUtil.lower,
                LCASE:        StringUtil.lower,
                LPAD:        StringUtil.lpad,
                MID:        StringUtil.substring,
                POSITION:    StringUtil.position,
                REVERSE:    StringUtil.reverse,
                REPEAT:        StringUtil.repeat,
                REPLACE:    StringUtil.replace,
                RIGHT:        StringUtil.right,
                RPAD:        StringUtil.rpad,
                SPACE:        StringUtil.space,
                SUBSTRING:    StringUtil.substring,
                UPPER:        StringUtil.upper,
                UCASE:        StringUtil.upper,

                // Date/Time Functions
                DAY:        DateUtil.day,
                DAYOFWEEK:    DateUtil.dayOfWeek,
                HOUR:        DateUtil.hour,
                MICROSECOND:DateUtil.microsecond,
                MINUTE:        DateUtil.minute,
                MONTH:        DateUtil.month,
                NOW:        DateUtil.now,
                SECOND:        DateUtil.second,
                YEAR:        DateUtil.year
            };

        } // end of class Fn
    }