OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2005 Maksim Orlovich <maksim@kde.org> | 2 * Copyright 2005 Maksim Orlovich <maksim@kde.org> |
3 * Copyright (C) 2006 Apple Computer, Inc. | 3 * Copyright (C) 2006 Apple Computer, Inc. |
4 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> | 4 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org> |
5 * | 5 * |
6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
8 * are met: | 8 * are met: |
9 * | 9 * |
10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
(...skipping 11 matching lines...) Expand all Loading... |
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 */ | 26 */ |
27 | 27 |
28 #include "config.h" | 28 #include "config.h" |
29 #include "core/xml/XPathParser.h" | 29 #include "core/xml/XPathParser.h" |
30 | 30 |
31 #include "bindings/v8/ExceptionState.h" | 31 #include "bindings/v8/ExceptionState.h" |
| 32 #include "core/XPathGrammar.h" |
32 #include "core/dom/ExceptionCode.h" | 33 #include "core/dom/ExceptionCode.h" |
33 #include "core/xml/XPathEvaluator.h" | 34 #include "core/xml/XPathEvaluator.h" |
34 #include "core/xml/XPathNSResolver.h" | 35 #include "core/xml/XPathNSResolver.h" |
35 #include "core/xml/XPathPath.h" | 36 #include "core/xml/XPathPath.h" |
36 #include "wtf/StdLibExtras.h" | 37 #include "wtf/StdLibExtras.h" |
37 #include "wtf/text/StringHash.h" | 38 #include "wtf/text/StringHash.h" |
38 | 39 |
39 using namespace WebCore; | 40 using namespace WebCore; |
40 using namespace WTF; | 41 using namespace WTF; |
41 using namespace Unicode; | 42 using namespace Unicode; |
42 using namespace XPath; | 43 using namespace XPath; |
43 | 44 |
44 #include "core/XPathGrammar.h" | |
45 | |
46 Parser* Parser::currentParser = 0; | 45 Parser* Parser::currentParser = 0; |
47 | 46 |
48 enum XMLCat { NameStart, NameCont, NotPartOfName }; | 47 enum XMLCat { NameStart, NameCont, NotPartOfName }; |
49 | 48 |
50 typedef HashMap<String, Step::Axis> AxisNamesMap; | 49 typedef HashMap<String, Step::Axis> AxisNamesMap; |
51 | 50 |
52 static XMLCat charCat(UChar aChar) | 51 static XMLCat charCat(UChar aChar) |
53 { | 52 { |
54 //### might need to add some special cases from the XML spec. | 53 // might need to add some special cases from the XML spec. |
55 | 54 |
56 if (aChar == '_') | 55 if (aChar == '_') |
57 return NameStart; | 56 return NameStart; |
58 | 57 |
59 if (aChar == '.' || aChar == '-') | 58 if (aChar == '.' || aChar == '-') |
60 return NameCont; | 59 return NameCont; |
61 CharCategory category = Unicode::category(aChar); | 60 CharCategory category = Unicode::category(aChar); |
62 if (category & (Letter_Uppercase | Letter_Lowercase | Letter_Other | Letter_
Titlecase | Number_Letter)) | 61 if (category & (Letter_Uppercase | Letter_Lowercase | Letter_Other | Letter_
Titlecase | Number_Letter)) |
63 return NameStart; | 62 return NameStart; |
64 if (category & (Mark_NonSpacing | Mark_SpacingCombining | Mark_Enclosing | L
etter_Modifier | Number_DecimalDigit)) | 63 if (category & (Mark_NonSpacing | Mark_SpacingCombining | Mark_Enclosing | L
etter_Modifier | Number_DecimalDigit)) |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 } | 199 } |
201 | 200 |
202 Token Parser::lexNumber() | 201 Token Parser::lexNumber() |
203 { | 202 { |
204 int startPos = m_nextPos; | 203 int startPos = m_nextPos; |
205 bool seenDot = false; | 204 bool seenDot = false; |
206 | 205 |
207 // Go until end or a non-digits character. | 206 // Go until end or a non-digits character. |
208 for (; m_nextPos < m_data.length(); ++m_nextPos) { | 207 for (; m_nextPos < m_data.length(); ++m_nextPos) { |
209 UChar aChar = m_data[m_nextPos]; | 208 UChar aChar = m_data[m_nextPos]; |
210 if (aChar >= 0xff) break; | 209 if (aChar >= 0xff) |
| 210 break; |
211 | 211 |
212 if (aChar < '0' || aChar > '9') { | 212 if (aChar < '0' || aChar > '9') { |
213 if (aChar == '.' && !seenDot) | 213 if (aChar == '.' && !seenDot) |
214 seenDot = true; | 214 seenDot = true; |
215 else | 215 else |
216 break; | 216 break; |
217 } | 217 } |
218 } | 218 } |
219 | 219 |
220 return Token(NUMBER, m_data.substring(startPos, m_nextPos - startPos)); | 220 return Token(NUMBER, m_data.substring(startPos, m_nextPos - startPos)); |
221 } | 221 } |
222 | 222 |
223 bool Parser::lexNCName(String& name) | 223 bool Parser::lexNCName(String& name) |
224 { | 224 { |
225 int startPos = m_nextPos; | 225 int startPos = m_nextPos; |
226 if (m_nextPos >= m_data.length()) | 226 if (m_nextPos >= m_data.length()) |
227 return false; | 227 return false; |
228 | 228 |
229 if (charCat(m_data[m_nextPos]) != NameStart) | 229 if (charCat(m_data[m_nextPos]) != NameStart) |
230 return false; | 230 return false; |
231 | 231 |
232 // Keep going until we get a character that's not good for names. | 232 // Keep going until we get a character that's not good for names. |
233 for (; m_nextPos < m_data.length(); ++m_nextPos) | 233 for (; m_nextPos < m_data.length(); ++m_nextPos) { |
234 if (charCat(m_data[m_nextPos]) == NotPartOfName) | 234 if (charCat(m_data[m_nextPos]) == NotPartOfName) |
235 break; | 235 break; |
| 236 } |
236 | 237 |
237 name = m_data.substring(startPos, m_nextPos - startPos); | 238 name = m_data.substring(startPos, m_nextPos - startPos); |
238 return true; | 239 return true; |
239 } | 240 } |
240 | 241 |
241 bool Parser::lexQName(String& name) | 242 bool Parser::lexQName(String& name) |
242 { | 243 { |
243 String n1; | 244 String n1; |
244 if (!lexNCName(n1)) | 245 if (!lexNCName(n1)) |
245 return false; | 246 return false; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 } | 290 } |
290 case '/': | 291 case '/': |
291 if (peekAheadHelper() == '/') | 292 if (peekAheadHelper() == '/') |
292 return makeTokenAndAdvance(SLASHSLASH, 2); | 293 return makeTokenAndAdvance(SLASHSLASH, 2); |
293 return makeTokenAndAdvance('/'); | 294 return makeTokenAndAdvance('/'); |
294 case '+': | 295 case '+': |
295 return makeTokenAndAdvance(PLUS); | 296 return makeTokenAndAdvance(PLUS); |
296 case '-': | 297 case '-': |
297 return makeTokenAndAdvance(MINUS); | 298 return makeTokenAndAdvance(MINUS); |
298 case '=': | 299 case '=': |
299 return makeTokenAndAdvance(EQOP, EqTestOp::OP_EQ); | 300 return makeTokenAndAdvance(EQOP, EqTestOp::OpcodeEqual); |
300 case '!': | 301 case '!': |
301 if (peekAheadHelper() == '=') | 302 if (peekAheadHelper() == '=') |
302 return makeTokenAndAdvance(EQOP, EqTestOp::OP_NE, 2); | 303 return makeTokenAndAdvance(EQOP, EqTestOp::OpcodeNotEqual, 2); |
303 return Token(XPATH_ERROR); | 304 return Token(XPATH_ERROR); |
304 case '<': | 305 case '<': |
305 if (peekAheadHelper() == '=') | 306 if (peekAheadHelper() == '=') |
306 return makeTokenAndAdvance(RELOP, EqTestOp::OP_LE, 2); | 307 return makeTokenAndAdvance(RELOP, EqTestOp::OpcodeLessOrEqual, 2); |
307 return makeTokenAndAdvance(RELOP, EqTestOp::OP_LT); | 308 return makeTokenAndAdvance(RELOP, EqTestOp::OpcodeLessThan); |
308 case '>': | 309 case '>': |
309 if (peekAheadHelper() == '=') | 310 if (peekAheadHelper() == '=') |
310 return makeTokenAndAdvance(RELOP, EqTestOp::OP_GE, 2); | 311 return makeTokenAndAdvance(RELOP, EqTestOp::OpcodeGreaterOrEqual, 2)
; |
311 return makeTokenAndAdvance(RELOP, EqTestOp::OP_GT); | 312 return makeTokenAndAdvance(RELOP, EqTestOp::OpcodeGreaterThan); |
312 case '*': | 313 case '*': |
313 if (isBinaryOperatorContext()) | 314 if (isBinaryOperatorContext()) |
314 return makeTokenAndAdvance(MULOP, NumericOp::OP_Mul); | 315 return makeTokenAndAdvance(MULOP, NumericOp::OP_Mul); |
315 ++m_nextPos; | 316 ++m_nextPos; |
316 return Token(NAMETEST, "*"); | 317 return Token(NAMETEST, "*"); |
317 case '$': { // $ QName | 318 case '$': { // $ QName |
318 m_nextPos++; | 319 m_nextPos++; |
319 String name; | 320 String name; |
320 if (!lexQName(name)) | 321 if (!lexQName(name)) |
321 return Token(XPATH_ERROR); | 322 return Token(XPATH_ERROR); |
322 return Token(VARIABLEREFERENCE, name); | 323 return Token(VARIABLEREFERENCE, name); |
323 } | 324 } |
324 } | 325 } |
325 | 326 |
326 String name; | 327 String name; |
327 if (!lexNCName(name)) | 328 if (!lexNCName(name)) |
328 return Token(XPATH_ERROR); | 329 return Token(XPATH_ERROR); |
329 | 330 |
330 skipWS(); | 331 skipWS(); |
331 // If we're in an operator context, check for any operator names | 332 // If we're in an operator context, check for any operator names |
332 if (isBinaryOperatorContext()) { | 333 if (isBinaryOperatorContext()) { |
333 if (name == "and") //### hash? | 334 if (name == "and") // ### hash? |
334 return Token(AND); | 335 return Token(AND); |
335 if (name == "or") | 336 if (name == "or") |
336 return Token(OR); | 337 return Token(OR); |
337 if (name == "mod") | 338 if (name == "mod") |
338 return Token(MULOP, NumericOp::OP_Mod); | 339 return Token(MULOP, NumericOp::OP_Mod); |
339 if (name == "div") | 340 if (name == "div") |
340 return Token(MULOP, NumericOp::OP_Div); | 341 return Token(MULOP, NumericOp::OP_Div); |
341 } | 342 } |
342 | 343 |
343 // See whether we are at a : | 344 // See whether we are at a : |
344 if (peekCurHelper() == ':') { | 345 if (peekCurHelper() == ':') { |
345 m_nextPos++; | 346 m_nextPos++; |
346 // Any chance it's an axis name? | 347 // Any chance it's an axis name? |
347 if (peekCurHelper() == ':') { | 348 if (peekCurHelper() == ':') { |
348 m_nextPos++; | 349 m_nextPos++; |
349 | 350 |
350 //It might be an axis name. | 351 // It might be an axis name. |
351 Step::Axis axis; | 352 Step::Axis axis; |
352 if (isAxisName(name, axis)) | 353 if (isAxisName(name, axis)) |
353 return Token(AXISNAME, axis); | 354 return Token(AXISNAME, axis); |
354 // Ugh, :: is only valid in axis names -> error | 355 // Ugh, :: is only valid in axis names -> error |
355 return Token(XPATH_ERROR); | 356 return Token(XPATH_ERROR); |
356 } | 357 } |
357 | 358 |
358 // Seems like this is a fully qualified qname, or perhaps the * modified
one from NameTest | 359 // Seems like this is a fully qualified qname, or perhaps the * modified |
| 360 // one from NameTest |
359 skipWS(); | 361 skipWS(); |
360 if (peekCurHelper() == '*') { | 362 if (peekCurHelper() == '*') { |
361 m_nextPos++; | 363 m_nextPos++; |
362 return Token(NAMETEST, name + ":*"); | 364 return Token(NAMETEST, name + ":*"); |
363 } | 365 } |
364 | 366 |
365 // Make a full qname. | 367 // Make a full qname. |
366 String n2; | 368 String n2; |
367 if (!lexNCName(n2)) | 369 if (!lexNCName(n2)) |
368 return Token(XPATH_ERROR); | 370 return Token(XPATH_ERROR); |
369 | 371 |
370 name = name + ":" + n2; | 372 name = name + ":" + n2; |
371 } | 373 } |
372 | 374 |
373 skipWS(); | 375 skipWS(); |
374 if (peekCurHelper() == '(') { | 376 if (peekCurHelper() == '(') { |
375 //note: we don't swallow the (here! | 377 // Note: we don't swallow the ( here! |
376 | 378 |
377 //either node type of function name | 379 // Either node type of function name |
378 if (isNodeTypeName(name)) { | 380 if (isNodeTypeName(name)) { |
379 if (name == "processing-instruction") | 381 if (name == "processing-instruction") |
380 return Token(PI, name); | 382 return Token(PI, name); |
381 | 383 |
382 return Token(NODETYPE, name); | 384 return Token(NODETYPE, name); |
383 } | 385 } |
384 //must be a function name. | 386 // Must be a function name. |
385 return Token(FUNCTIONNAME, name); | 387 return Token(FUNCTIONNAME, name); |
386 } | 388 } |
387 | 389 |
388 // At this point, it must be NAMETEST. | 390 // At this point, it must be NAMETEST. |
389 return Token(NAMETEST, name); | 391 return Token(NAMETEST, name); |
390 } | 392 } |
391 | 393 |
392 Token Parser::nextToken() | 394 Token Parser::nextToken() |
393 { | 395 { |
394 Token toRet = nextTokenInternal(); | 396 Token toRet = nextTokenInternal(); |
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
630 #if !ENABLE(OILPAN) | 632 #if !ENABLE(OILPAN) |
631 if (t == 0) | 633 if (t == 0) |
632 return; | 634 return; |
633 | 635 |
634 ASSERT(m_nodeTests.contains(t)); | 636 ASSERT(m_nodeTests.contains(t)); |
635 | 637 |
636 m_nodeTests.remove(t); | 638 m_nodeTests.remove(t); |
637 #endif | 639 #endif |
638 } | 640 } |
639 | 641 |
OLD | NEW |