Files
palemoon27/dom/xslt/xpath/txExprLexer.cpp
T
roytam1 68ea640f88 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1246575 - Inline RegExp.prototype.{global,ignoreCase,multiline,sticky,unicode} getters. r=h4writer (4c1dd91f65)
- Bug 1240796 - Inline SIMD operations that return scalars. r=bbouvier (e9a4985d96)
- Bug 1241872: Fix inlining of SIMD extractLanes in self-hosting; r=jolesen (337ab5c171)
- Bug 1240796 - Detemplatize getOrCreateSimdTypeDescr(). r=bbouvier (d1721d193d)
- Bug 1240796 - Extract baseline code to GetTemplateObjectForSimd(). r=bbouvier (302921629a)
- Bug 1240796 - Connect SIMD.Uint32x4 operations to the Ion inliner. r=bbouvier (24a2e4801b)
- Bug 1243810: Remove storage class of SimdOperation; r=jolesen (b5f74d5d74)
- Bug 1224374 - Profiler labels for the 25 top chrome hangs;r=BenWa,MarcoZ (b0ee441936)
- Bug 1211401 - Use global message manager as parent of <iframe mozbrowser> MM (r=smaug,ahal) (496e94f133)
- When mix-blending, only copy intersecting backdrop pixels. (bug 1235995 part 2, r=mattwoodrow) (f3a2211866)
- Fix the backdrop copy rect in nested mix-blend containers. (bug 1241273, r=mstange) (00ae1f2375)
- Bug 1246403: Implement call_import when caller returns float32; r=luke (f59d6303a6)
- Bug 1239506 - Make console formatter return NaN instead of nan with %f;r=baku (44aa78fba7)
- Bug 1202735 - Add nsIObserver to avoid warning. r=eeejay (93bf7d87e7)
- Bug 1228134 - Should check media.webspeech.synth.enabled on Windows SAPI backend. r=eeejay (4e04c701cb)
- Bug 1003464 - Support Web Speech API synthesis via speech-dispatcher. r=kdavis (bc6c839f1d)
- Bug 1003452 - Implement OSX backend for WebSpeech Synthesis. r=eeejay (85c3b95baa)
- Bug 1223153 - Create new thread to enumerate voice items. r=eeejay (6246ad40a0)
- fix refptr (075d2a7614)
- Bug 1211974 - Implement nsIObserver in SpeechDispatcherService. r=smaug (1fe398291f)
- Bug 1227848 - Separate construction from off-main-thread setup in SpeechDispatcherService. r=smaug (df4e431ad0)
- Bug 1191667 - Part 1. Add onVolumeChanged method to nsISpeechTaskCallback. r=eitan (119271d432)
- Bug 1191667 - Part 2. Call onVolumeChanged when changing volume. r=eitan (9aeb12f90f)
- Bug 1191667 - Part 3. Call NotifyStartedPlaying to show audio indicator. r=eitan (7c0a62f004)
- Bug 1187151 (part 13) - Replace nsBaseHashtable::Enumerate() calls in dom/ with iterators. r=baku. (aac6428d17)
- Bug 1225928 - Fix hang on linux when sending an empty string to speech synth. r=smaug (f21d1d9c2e)
- Bug 1221520 - nullcheck for mSpeechdClient. r=eeejay (3b38bd7fda)
- Bug 1230428 - Part 1. Check mTask since end event is posted asynchronized. r=eeejay (5b5ecaddd8)
- Bug 1239494 - Followup to fix a spurious hazard analysis failure; r=meow (7c6eac2f31)
- Bug 1224374 - Profiler labels for the top 26-100 chrome hangs;r=BenWa (f3edb68e7e)
- Bug 1242214 - Rename JSPropertyDescriptor JS::PropertyDescriptor in js. r=sstangl (b5fa6fc75c)
- Bug 1242072 - Continue using getPropertyDescriptor for get in Sandbox. r=bholley (3315e39b91)
- Bug 1242072 - Continue using getPropertyDescriptor for get in XrayWrapper. r=bholley (d9506cbe6a)
- Bug 1242214 - Rename JSPropertyDescriptor JS::PropertyDescriptor everywhere else. r=smaug (f5bf388f8b)
- Bug 1239822: Part 1 - Add a close method to windowless browsers, and only destroy when safe. r=bz (28cd84032e)
- apply (and revert little bit of PM) Bug 1218364 - windowless browser windows should not crash on Troubleshoot. (2ef4a8e4f7)
- Bug 1224105 - [webext] Use <browser> element for background page (r=kmag) (34b4e7a807)
- Bug 1239822: Part 2a - [webext] Explicitly destroy windowless browsers on unload. r=billm (737d05f57c)
- Bug 1239822: Part 2b - Destroy windowless browsers created for add-on SDK page workers. (de9bcd0438)
- Bug 1239822: Part 2c - Destroy windowless browsers created by browser parsable CSS tests. r=gijs (6e04b09bc6)
- Bug 1217307 - Remove some unnecessary null checks in dom/xslt/. r=njn (4208056baf)
- Bug 1222624: Make XSLT stylesheet parsing use nsIPrincipals and nsIURIs rather than strings. r=peterv (34984e2115)
- Bug 1222475 - use UniquePtr<T[]> instead of nsAutoArrayPtr<T> in dom/; r=baku,bz,terrence (2d33fa1b22)
- Bug 1237445 - Use GCHashSet for BaseShapeSet and InitialShapeSet, r=terrence (a4c8056f3a)
- Bug 1244365 - Remove Traceable; r=sfink (5a7d3ed42e)
- Bug 1236473 - Do not merge scripts that didn't successfully compile. (r=jandem) (8f03cbd52c)
- Bug 1240416 Disallow setting GC mark stack size to zero, and assert on attempt to realloc() zero bytes r=terrence (f28ea7d8f3)
- Bug 1232113 - "Make the format specifiers in JS_snprintf() invocations more portable". r=sphink (deb4e3bd14)
- Bug 1232672 - Use MOZ_WARN_UNUSED_RESULT to make ordered hash table clients check for failure r=sfink (541737edf1)
- Bug 1220703 - Remove AutoDisableStoreBuffer; r=jonco (e1b44b7696)
- Bug 1236523 part 1 - Remove Shape NON_NATIVE flag. r=bhackett (64dfe2f282)
- Bug 1236523 part 2 - Cache isBigEnoughForAShapeTable on the Shape. r=bhackett (86b6c65dc6)
- Bug 1236523 part 3 - Templatize Shape::search and ShapeTable::search. r=bhackett (9ca2f75776)
2023-08-29 10:28:28 +08:00

368 lines
10 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Lexical analyzer for XPath expressions
*/
#include "txExprLexer.h"
#include "nsGkAtoms.h"
#include "nsString.h"
#include "nsError.h"
#include "txXMLUtils.h"
/**
* Creates a new ExprLexer
*/
txExprLexer::txExprLexer()
: mCurrentItem(nullptr),
mFirstItem(nullptr),
mLastItem(nullptr),
mTokenCount(0)
{
}
/**
* Destroys this instance of an txExprLexer
*/
txExprLexer::~txExprLexer()
{
//-- delete tokens
Token* tok = mFirstItem;
while (tok) {
Token* temp = tok->mNext;
delete tok;
tok = temp;
}
mCurrentItem = nullptr;
}
Token*
txExprLexer::nextToken()
{
if (!mCurrentItem) {
NS_NOTREACHED("nextToken called on uninitialized lexer");
return nullptr;
}
if (mCurrentItem->mType == Token::END) {
// Do not progress beyond the end token
return mCurrentItem;
}
Token* token = mCurrentItem;
mCurrentItem = mCurrentItem->mNext;
return token;
}
void
txExprLexer::addToken(Token* aToken)
{
if (mLastItem) {
mLastItem->mNext = aToken;
}
if (!mFirstItem) {
mFirstItem = aToken;
mCurrentItem = aToken;
}
mLastItem = aToken;
++mTokenCount;
}
/**
* Returns true if the following Token should be an operator.
* This is a helper for the first bullet of [XPath 3.7]
* Lexical Structure
*/
bool
txExprLexer::nextIsOperatorToken(Token* aToken)
{
if (!aToken || aToken->mType == Token::NULL_TOKEN) {
return false;
}
/* This relies on the tokens having the right order in txExprLexer.h */
return aToken->mType < Token::COMMA ||
aToken->mType > Token::UNION_OP;
}
/**
* Parses the given string into a sequence of Tokens
*/
nsresult
txExprLexer::parse(const nsASingleFragmentString& aPattern)
{
iterator start, end;
start = aPattern.BeginReading(mPosition);
aPattern.EndReading(end);
//-- initialize previous token, this will automatically get
//-- deleted when it goes out of scope
Token nullToken(nullptr, nullptr, Token::NULL_TOKEN);
Token::Type defType;
Token* newToken = nullptr;
Token* prevToken = &nullToken;
bool isToken;
while (mPosition < end) {
defType = Token::CNAME;
isToken = true;
if (*mPosition == DOLLAR_SIGN) {
if (++mPosition == end || !XMLUtils::isLetter(*mPosition)) {
return NS_ERROR_XPATH_INVALID_VAR_NAME;
}
defType = Token::VAR_REFERENCE;
}
// just reuse the QName parsing, which will use defType
// the token to construct
if (XMLUtils::isLetter(*mPosition)) {
// NCName, can get QName or OperatorName;
// FunctionName, NodeName, and AxisSpecifier may want whitespace,
// and are dealt with below
start = mPosition;
while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
/* just go */
}
if (mPosition < end && *mPosition == COLON) {
// try QName or wildcard, might need to step back for axis
if (++mPosition == end) {
return NS_ERROR_XPATH_UNEXPECTED_END;
}
if (XMLUtils::isLetter(*mPosition)) {
while (++mPosition < end && XMLUtils::isNCNameChar(*mPosition)) {
/* just go */
}
}
else if (*mPosition == '*' && defType != Token::VAR_REFERENCE) {
// eat wildcard for NameTest, bail for var ref at COLON
++mPosition;
}
else {
--mPosition; // step back
}
}
if (nextIsOperatorToken(prevToken)) {
nsDependentSubstring op(Substring(start, mPosition));
if (nsGkAtoms::_and->Equals(op)) {
defType = Token::AND_OP;
}
else if (nsGkAtoms::_or->Equals(op)) {
defType = Token::OR_OP;
}
else if (nsGkAtoms::mod->Equals(op)) {
defType = Token::MODULUS_OP;
}
else if (nsGkAtoms::div->Equals(op)) {
defType = Token::DIVIDE_OP;
}
else {
// XXX QUESTION: spec is not too precise
// badops is sure an error, but is bad:ops, too? We say yes!
return NS_ERROR_XPATH_OPERATOR_EXPECTED;
}
}
newToken = new Token(start, mPosition, defType);
}
else if (isXPathDigit(*mPosition)) {
start = mPosition;
while (++mPosition < end && isXPathDigit(*mPosition)) {
/* just go */
}
if (mPosition < end && *mPosition == '.') {
while (++mPosition < end && isXPathDigit(*mPosition)) {
/* just go */
}
}
newToken = new Token(start, mPosition, Token::NUMBER);
}
else {
switch (*mPosition) {
//-- ignore whitespace
case SPACE:
case TX_TAB:
case TX_CR:
case TX_LF:
++mPosition;
isToken = false;
break;
case S_QUOTE :
case D_QUOTE :
start = mPosition;
while (++mPosition < end && *mPosition != *start) {
// eat literal
}
if (mPosition == end) {
mPosition = start;
return NS_ERROR_XPATH_UNCLOSED_LITERAL;
}
newToken = new Token(start + 1, mPosition, Token::LITERAL);
++mPosition;
break;
case PERIOD:
// period can be .., .(DIGITS)+ or ., check next
if (++mPosition == end) {
newToken = new Token(mPosition - 1, Token::SELF_NODE);
}
else if (isXPathDigit(*mPosition)) {
start = mPosition - 1;
while (++mPosition < end && isXPathDigit(*mPosition)) {
/* just go */
}
newToken = new Token(start, mPosition, Token::NUMBER);
}
else if (*mPosition == PERIOD) {
++mPosition;
newToken = new Token(mPosition - 2, mPosition, Token::PARENT_NODE);
}
else {
newToken = new Token(mPosition - 1, Token::SELF_NODE);
}
break;
case COLON: // QNames are dealt above, must be axis ident
if (++mPosition >= end || *mPosition != COLON ||
prevToken->mType != Token::CNAME) {
return NS_ERROR_XPATH_BAD_COLON;
}
prevToken->mType = Token::AXIS_IDENTIFIER;
++mPosition;
isToken = false;
break;
case FORWARD_SLASH :
if (++mPosition < end && *mPosition == FORWARD_SLASH) {
++mPosition;
newToken = new Token(mPosition - 2, mPosition, Token::ANCESTOR_OP);
}
else {
newToken = new Token(mPosition - 1, Token::PARENT_OP);
}
break;
case BANG : // can only be !=
if (++mPosition < end && *mPosition == EQUAL) {
++mPosition;
newToken = new Token(mPosition - 2, mPosition, Token::NOT_EQUAL_OP);
break;
}
// Error ! is not not()
return NS_ERROR_XPATH_BAD_BANG;
case EQUAL:
newToken = new Token(mPosition, Token::EQUAL_OP);
++mPosition;
break;
case L_ANGLE:
if (++mPosition == end) {
return NS_ERROR_XPATH_UNEXPECTED_END;
}
if (*mPosition == EQUAL) {
++mPosition;
newToken = new Token(mPosition - 2, mPosition,
Token::LESS_OR_EQUAL_OP);
}
else {
newToken = new Token(mPosition - 1, Token::LESS_THAN_OP);
}
break;
case R_ANGLE:
if (++mPosition == end) {
return NS_ERROR_XPATH_UNEXPECTED_END;
}
if (*mPosition == EQUAL) {
++mPosition;
newToken = new Token(mPosition - 2, mPosition,
Token::GREATER_OR_EQUAL_OP);
}
else {
newToken = new Token(mPosition - 1, Token::GREATER_THAN_OP);
}
break;
case HYPHEN :
newToken = new Token(mPosition, Token::SUBTRACTION_OP);
++mPosition;
break;
case ASTERISK:
if (nextIsOperatorToken(prevToken)) {
newToken = new Token(mPosition, Token::MULTIPLY_OP);
}
else {
newToken = new Token(mPosition, Token::CNAME);
}
++mPosition;
break;
case L_PAREN:
if (prevToken->mType == Token::CNAME) {
const nsDependentSubstring& val = prevToken->Value();
if (val.EqualsLiteral("comment")) {
prevToken->mType = Token::COMMENT_AND_PAREN;
}
else if (val.EqualsLiteral("node")) {
prevToken->mType = Token::NODE_AND_PAREN;
}
else if (val.EqualsLiteral("processing-instruction")) {
prevToken->mType = Token::PROC_INST_AND_PAREN;
}
else if (val.EqualsLiteral("text")) {
prevToken->mType = Token::TEXT_AND_PAREN;
}
else {
prevToken->mType = Token::FUNCTION_NAME_AND_PAREN;
}
isToken = false;
}
else {
newToken = new Token(mPosition, Token::L_PAREN);
}
++mPosition;
break;
case R_PAREN:
newToken = new Token(mPosition, Token::R_PAREN);
++mPosition;
break;
case L_BRACKET:
newToken = new Token(mPosition, Token::L_BRACKET);
++mPosition;
break;
case R_BRACKET:
newToken = new Token(mPosition, Token::R_BRACKET);
++mPosition;
break;
case COMMA:
newToken = new Token(mPosition, Token::COMMA);
++mPosition;
break;
case AT_SIGN :
newToken = new Token(mPosition, Token::AT_SIGN);
++mPosition;
break;
case PLUS:
newToken = new Token(mPosition, Token::ADDITION_OP);
++mPosition;
break;
case VERT_BAR:
newToken = new Token(mPosition, Token::UNION_OP);
++mPosition;
break;
default:
// Error, don't grok character :-(
return NS_ERROR_XPATH_ILLEGAL_CHAR;
}
}
if (isToken) {
NS_ENSURE_TRUE(newToken, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE(newToken != mLastItem, NS_ERROR_FAILURE);
prevToken = newToken;
addToken(newToken);
}
}
// add a endToken to the list
newToken = new Token(end, end, Token::END);
addToken(newToken);
return NS_OK;
}