    package flare.query
    {
        /**
         * Expression operator for text matching operations. Performs prefix,
         * suffix, containment, and regular expression matching.
         */
        public class Match extends BinaryExpression
        {
            /** Indicates a prefix matching test. */
            public static const PREFIX:int = 0;
            /** Indicates a suffix matching test. */
            public static const SUFFIX:int = 1;
            /** Indicates a string containment test. */
            public static const WITHIN:int = 2;
            /** Indicates a regular expression matching test. */
            public static const REGEXP:int = 3;

            /** Returns a string representation of the string matching operator. */
            public override function get operatorString():String
            {
                switch (_op) {
                    case PREFIX: return 'STARTS-WITH';
                    case SUFFIX: return 'ENDS-WITH';
                    case WITHIN: return 'CONTAINS';
                    case REGEXP: return 'REGEXP';
                    default: return '?';
                }
            }

            /**
             * Create a new Match expression.
             * @param operation the operation to perform
             * @param left the left sub-expression
             * @param right the right sub-expression
             */
            public function Match(op:int, left:*, right:*)
            {
                super(op, PREFIX, REGEXP, left, right);
            }

            /**
             * @inheritDoc
             */
            public override function clone():Expression
            {
                return new Match(_op, _left.clone(), _right.clone());
            }

            /**
             * @inheritDoc
             */
            public override function eval(o:Object=null):*
            {
                var s:String = String(_left.eval(o));
                var p:String = String(_right.eval(o));

                // compute return value
                switch (_op) {
                    case PREFIX: return StringUtil.startsWith(s, p);
                    case SUFFIX: return StringUtil.endsWith(s, p);
                    case WITHIN: return s.indexOf(p) >= 0;
                    case REGEXP: return parseRegExp(p).test(s);
                }
                throw new Error("Unknown operation type: "+_op);
            }

            private var cachedRegExp:RegExp;
            private var cachedPattern:String;

            private function parseRegExp(p:String):RegExp
            {
                if (p == cachedPattern) return cachedRegExp;

                cachedPattern = p;
                var tok:Array = p.split("/");
                cachedRegExp = new RegExp(tok[1], tok[2]);
                return cachedRegExp;
            }

            // -- Static constructors ---------------------------------------------

            /**
             * Creates a new Match operator for matching string prefix.
             * @param left the left-hand input expression
             * @param right the right-hand input expression
             * @return the new Match operator
             */
            public static function StartsWith(left:*, right:*):Match
            {
                return new Match(PREFIX, left, right);
            }

            /**
             * Creates a new Match operator for matching a string suffix.
             * @param left the left-hand input expression
             * @param right the right-hand input expression
             * @return the new Match operator
             */
            public static function EndsWith(left:*, right:*):Match
            {
                return new Match(SUFFIX, left, right);
            }

            /**
             * Creates a new Match operator for matching string containment.
             * @param left the left-hand input expression
             * @param right the right-hand input expression
             * @return the new Match operator
             */
            public static function Contains(left:*, right:*):Match
            {
                return new Match(WITHIN, left, right);
            }

            /**
             * Creates a new Match operator for matching a regular expression.
             * @param left the left-hand input expression
             * @param right the right-hand input expression
             * @return the new Match operator
             */
            public static function RegEx(left:*, right:*):Match
            {
                return new Match(REGEXP, left, right);
            }

        } // end of class Match
    }