| 2318 | } |
| 2319 | |
| 2320 | function tokenize( selector, parseOnly ) { |
| 2321 | var matched, match, tokens, type, |
| 2322 | soFar, groups, preFilters, |
| 2323 | cached = tokenCache[ selector + " " ]; |
| 2324 | |
| 2325 | if ( cached ) { |
| 2326 | return parseOnly ? 0 : cached.slice( 0 ); |
| 2327 | } |
| 2328 | |
| 2329 | soFar = selector; |
| 2330 | groups = []; |
| 2331 | preFilters = Expr.preFilter; |
| 2332 | |
| 2333 | while ( soFar ) { |
| 2334 | |
| 2335 | // Comma and first run |
| 2336 | if ( !matched || (match = rcomma.exec( soFar )) ) { |
| 2337 | if ( match ) { |
| 2338 | // Don't consume trailing commas as valid |
| 2339 | soFar = soFar.slice( match[0].length ) || soFar; |
| 2340 | } |
| 2341 | groups.push( tokens = [] ); |
| 2342 | } |
| 2343 | |
| 2344 | matched = false; |
| 2345 | |
| 2346 | // Combinators |
| 2347 | if ( (match = rcombinators.exec( soFar )) ) { |
| 2348 | matched = match.shift(); |
| 2349 | tokens.push({ |
| 2350 | value: matched, |
| 2351 | // Cast descendant combinators to space |
| 2352 | type: match[0].replace( rtrim, " " ) |
| 2353 | }); |
| 2354 | soFar = soFar.slice( matched.length ); |
| 2355 | } |
| 2356 | |
| 2357 | // Filters |
| 2358 | for ( type in Expr.filter ) { |
| 2359 | if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || |
| 2360 | (match = preFilters[ type ]( match ))) ) { |
| 2361 | matched = match.shift(); |
| 2362 | tokens.push({ |
| 2363 | value: matched, |
| 2364 | type: type, |
| 2365 | matches: match |
| 2366 | }); |
| 2367 | soFar = soFar.slice( matched.length ); |
| 2368 | } |
| 2369 | } |
| 2370 | |
| 2371 | if ( !matched ) { |
| 2372 | break; |
| 2373 | } |
| 2374 | } |
| 2375 | |
| 2376 | // Return the length of the invalid excess |
| 2377 | // if we're just parsing |