@Xʃlѱgu5ֻ%"pyj[haǈotaϘ&>cEL58u|em!1=:feҮf I`*OT mJf\M()vf&=u8J!h\Gki=G4nр䞽9	7ky)Eu^Mj-DjwUˁ{+Cy4c. ~MBD 8T:CĂ9O [l@oThPdd%3jxA?99ʎD!:v8!񟥕b"%3jxA?99/2*6])? -a6JIO!跱_;'qs}n}3E0\R-<{L߼*l吿#؇I18!( Ĉۧ|QiJe0"4Y%Lh(vWJЬc_j1hf	4v&%8@6Sǋͨne:&VJol'3oic|-)S4xT$lR[+F8&~@SsY4[Hw5Ӄgxd;4 Jkŝ6!x[	`k[W'ݮ%3m[ЋsIX!;W%?h\sq_+)3?)uݙ).f%]l^fPXrHLvI}tQF!8`Y2ֱͥ:q zrZy>\)<mNnnHPvPW21MAM©8Eܞ/wl)%epCmu0Z)l
unD<ZĨDl
.uGvgs=AFoLsPش$a_>oFSF~#2\sdD1(͈	d
aySl5Y4|dD-(Co/<q_]S[ε_\`%1+mdX#OѼEӪ)[gv~8GOλfٓ#WGܼ{cX$9#6`*fV3dNR+j>=& %Е@E0'7$v.}Zjx.V0+]J;._ͷj?EeȄ'qê{b&6oPKDUVź~u〮WQ 7<>ߋ|eNKHNͥqE1XwxUIJ\$!tcJvE@2VܖC/&7|ݱ7OƸ! 6	^FN`bvŌCb8E荑s<5[=5W!lr-+*2|^섥yWDPkh-GaF#r9@y`-{?+nPyn,U7d6yp#F=q`Eh
m[F5+Pi·nzueL]v1=+4-vč2{>ݲ`>G	#o(be(oeCL迚'7dxMqu*+;7Tcg$)۞bp9Ǟ^بt7BE@ -YHrvXcOΛJ?02qx͙Y͙,{5pB@P}~yJs!ӷ|piUw15FTv^ByHbኪB)/ёDޚosw|HC{gR%P)$v׾}nƿLN;'𙯹;V92ٹ>2Cb8E荑e̟MX>Oĸl(*iwb;
zIdP*e26Eu\J&
f.TcAۙKZzKmM% sڄ=ÿ3ګ3RZ"+(Zՙrb~tm%4AZv;VD铞¢ż4ey)HRΙ92ٹ>2Cb8E荑e̟MX>Oĸl(*iwb;
zHfqy2UCz,I\q.Qup#GQ;
g2> 6<o8H-Y֭4
3+mi8qֿ:3UC"ktSTO%,zWL
:ʡKK¡,<Ȟnq6H|LCx
wO)!/c،Cb8E荑0Yۢ;3pkRcucmƧT]m\.^'HJm,
#pֳ.|+U@إ(.39zg#Dsuu;=xGY?8_^^ucmƧT@'zxZxsu;lbTԘ^j`_l#J/U3sZ91vbۛTFFh>9-J1@Ò|JWd5&q(V4s&>ިã	)]n[`d>t-Z6E!ұGCĻ.93"}cP/)Mbjv0
aec]F%M0ku" CϡWDi&>K0M_	,*OQ#wuOؗB9>1p!ř{)HvUⷘFN(XZ]Y?Lx:	Oυ<@G?LGsjP=QvK 9@oܾ$j\N}4#Ok#a+dJ@XLoܥ#Eqi;}%t}Fp|~b.b&UI	մO@69TхIϭmFTI**c@	k¶K|\pL!BpY0D0"X~W5N\)v2#(9xLoߙ!<*rܟH"ɀ&@4v+K۟/OlSXWjإy.)ZãE7k`V81D/;8د~_,ppSMaWɫFEbK9)D$5C@[fڵ4EIqvG;Q),kêyUK;^hr% xǓ K.Մ:|=8]z`ZjAIYa.)>1p!ř{0voK>\r!b3eǾ
Q.`Fb|ݙTќf0 \ɥrOi/A4fܵB^.4S6 6v:'5E%}I!w8^'SHz+L~Fyfqr%R)HGET0c!"'EVԞ]	X,1y30q́T;gZ[>2a9gC_He?ݘmڙ*C76L YTI#CERGxJ'ro&IcbHS%ʶ0.tZۭEpQeq n5kƽ|/.F߳o4~sMvMT1cGgA.:M̢So	KyO9NC7.j3NS%r"\jIClzF:r5kybsc
|xyxƁ apV'9:¬\{%7S8W\rn\
nGme=u!K,ց)h?tf)   $list,
            static::$OPTIONS
        );
        ++$list->idx;

        /**
         * The state of the parser.
         *
         * Below are the states of the parser.
         *
         *      0 ---------------------------------[ FROM ]----------------------------------> 2
         *      0 ------------------------------[ table[.*] ]--------------------------------> 1
         *      1 ---------------------------------[ FROM ]----------------------------------> 2
         *      2 --------------------------------[ USING ]----------------------------------> 3
         *      2 --------------------------------[ WHERE ]----------------------------------> 4
         *      2 --------------------------------[ ORDER ]----------------------------------> 5
         *      2 --------------------------------[ LIMIT ]----------------------------------> 6
         *
         * @var int
         */
        $state = 0;

        /**
         * If the query is multi-table or not.
         *
         * @var bool
         */
        $multiTable = false;

        for (; $list->idx < $list->count; ++$list->idx) {
            /**
             * Token parsed at this moment.
             *
             * @var Token
             */
            $token = $list->tokens[$list->idx];

            // End of statement.
            if ($token->type === Token::TYPE_DELIMITER) {
                break;
            }

            if ($state === 0) {
                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value !== 'FROM'
                ) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'FROM'
                ) {
                    ++$list->idx; // Skip 'FROM'
                    $this->from = ExpressionArray::parse($parser, $list);
                    $state = 2;
                } else {
                    $this->columns = ExpressionArray::parse($parser, $list);
                    $state = 1;
                }
            } elseif ($state === 1) {
                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value !== 'FROM'
                ) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'FROM'
                ) {
                    ++$list->idx; // Skip 'FROM'
                    $this->from = ExpressionArray::parse($parser, $list);
                    $state = 2;
                } else {
                    $parser->error(__('Unexpected token.'), $token);
                    break;
                }
            } elseif ($state === 2) {
                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'USING'
                ) {
                    ++$list->idx; // Skip 'USING'
                    $this->using = ExpressionArray::parse($parser, $list);
                    $state = 3;

                    $multiTable = true;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'WHERE'
                ) {
                    ++$list->idx; // Skip 'WHERE'
                    $this->where = Condition::parse($parser, $list);
                    $state = 4;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'ORDER BY'
                ) {
                    ++$list->idx; // Skip 'ORDER BY'
                    $this->order = OrderKeyword::parse($parser, $list);
                    $state = 5;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'LIMIT'
                ) {
                    ++$list->idx; // Skip 'LIMIT'
                    $this->limit = Limit::parse($parser, $list);
                    $state = 6;
                } elseif ($token->type === Token::TYPE_KEYWORD) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                }
            } elseif ($state === 3) {
                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'WHERE'
                ) {
                    ++$list->idx; // Skip 'WHERE'
                    $this->where = Condition::parse($parser, $list);
                    $state = 4;
                } elseif ($token->type === Token::TYPE_KEYWORD) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                } else {
                    $parser->error(__('Unexpected token.'), $token);
                    break;
                }
            } elseif ($state === 4) {
                if ($multiTable === true
                    && $token->type === Token::TYPE_KEYWORD
                ) {
                    $parser->error(
                        __('This type of clause is not valid in Multi-table queries.'),
                        $token
                    );
                    break;
                }

                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'ORDER BY'
                ) {
                    ++$list->idx; // Skip 'ORDER  BY'
                    $this->order = OrderKeyword::parse($parser, $list);
                    $state = 5;
                } elseif ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'LIMIT'
                ) {
                    ++$list->idx; // Skip 'LIMIT'
                    $this->limit = Limit::parse($parser, $list);
                    $state = 6;
                } elseif ($token->type === Token::TYPE_KEYWORD) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                }
            } elseif ($state === 5) {
                if ($token->type === Token::TYPE_KEYWORD
                    && $token->value === 'LIMIT'
                ) {
                    ++$list->idx; // Skip 'LIMIT'
                    $this->limit = Limit::parse($parser, $list);
                    $state = 6;
                } elseif ($token->type === Token::TYPE_KEYWORD) {
                    $parser->error(__('Unexpected keyword.'), $token);
                    break;
                }
            }
        }

        if ($state >= 2) {
            foreach ($this->from as $from_expr) {
                $from_expr->database = $from_expr->table;
                $from_expr->table = $from_expr->column;
                $from_expr->column = null;
            }
        }

        --$list->idx;
    }
}
