Ignore:
Timestamp:
Jun 12, 2009, 6:18:57 PM (16 years ago)
Author:
[email protected]
Message:

Make LiteralParser non-recursive

Reviewed by Geoff Garen.

Convert LiteralParser from using a simple recursive descent parser
to a hand rolled PDA. Relatively simple conversion, but required
modifications to MarkedArgumentBuffer to make it more suitable as
a generic marked vector. I'll refactor and rename MarkedArgumentBuffer
in future as there are many other cases where it will be useful to
have such a class.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/LiteralParser.cpp

    r44343 r44644  
    3333namespace JSC {
    3434
    35 class LiteralParser::StackGuard {
    36 public:
    37     StackGuard(LiteralParser* parser)
    38         : m_parser(parser)
    39     {
    40         m_parser->m_depth++;
    41     }
    42     ~StackGuard()
    43     {
    44         m_parser->m_depth--;
    45     }
    46     bool isSafe() { return m_parser->m_depth < 10; }
    47 private:
    48     LiteralParser* m_parser;
    49 };
    50 
    5135static bool isSafeStringCharacter(UChar c)
    5236{
     
    198182}
    199183
    200 JSValue LiteralParser::parseStatement()
    201 {
    202     StackGuard guard(this);
    203     if (!guard.isSafe())
    204         return abortParse();
    205 
    206     switch (m_lexer.currentToken().type) {
    207         case TokLBracket:
    208         case TokNumber:
    209         case TokString:
    210             return parseExpression();
    211         case TokLParen: {
    212             m_lexer.next();
    213             JSValue result = parseExpression();
    214             if (m_aborted || m_lexer.currentToken().type != TokRParen)
    215                 return abortParse();
    216             m_lexer.next();
    217             return result;
     184JSValue LiteralParser::parse(ParserState initialState)
     185{
     186    ParserState state = initialState;
     187    MarkedArgumentBuffer objectStack;
     188    JSValue lastValue;
     189    Vector<ParserState, 16> stateStack;
     190    Vector<Identifier, 16> identifierStack;
     191    while (1) {
     192        switch(state) {
     193            startParseArray:
     194            case StartParseArray: {
     195                JSArray* array = constructEmptyArray(m_exec);
     196                objectStack.append(array);
     197                // fallthrough
     198            }
     199            doParseArrayStartExpression:
     200            case DoParseArrayStartExpression: {
     201                if (m_lexer.next() == TokRBracket) {
     202                    m_lexer.next();
     203                    lastValue = objectStack.last();
     204                    objectStack.removeLast();
     205                    break;
     206                }
     207
     208                stateStack.append(DoParseArrayEndExpression);
     209                goto startParseExpression;
     210            }
     211            case DoParseArrayEndExpression: {
     212                 asArray(objectStack.last())->push(m_exec, lastValue);
     213               
     214                if (m_lexer.currentToken().type == TokComma)
     215                    goto doParseArrayStartExpression;
     216
     217                if (m_lexer.currentToken().type != TokRBracket)
     218                    return JSValue();
     219               
     220                m_lexer.next();
     221                lastValue = objectStack.last();
     222                objectStack.removeLast();
     223                break;
     224            }
     225            startParseObject:
     226            case StartParseObject: {
     227                JSObject* object = constructEmptyObject(m_exec);
     228                objectStack.append(object);
     229                // fallthrough
     230            }
     231            doParseObjectStartExpression:
     232            case DoParseObjectStartExpression: {
     233                TokenType type = m_lexer.next();
     234                if (type == TokString) {
     235                    Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
     236
     237                    // Check for colon
     238                    if (m_lexer.next() != TokColon)
     239                        return JSValue();
     240
     241                    m_lexer.next();
     242                    identifierStack.append(Identifier(m_exec, identifierToken.start + 1, identifierToken.end - identifierToken.start - 2));
     243                    stateStack.append(DoParseObjectEndExpression);
     244                    goto startParseExpression;
     245                } else if (type != TokRBrace)
     246                    return JSValue();
     247                m_lexer.next();
     248                lastValue = objectStack.last();
     249                objectStack.removeLast();
     250                break;
     251            }
     252            case DoParseObjectEndExpression:
     253            {
     254                asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue);
     255                identifierStack.removeLast();
     256                if (m_lexer.currentToken().type == TokComma)
     257                    goto doParseObjectStartExpression;
     258                if (m_lexer.currentToken().type != TokRBrace)
     259                    return JSValue();
     260                m_lexer.next();
     261                lastValue = objectStack.last();
     262                objectStack.removeLast();
     263                break;
     264            }
     265            startParseExpression:
     266            case StartParseExpression: {
     267                switch (m_lexer.currentToken().type) {
     268                    case TokLBracket:
     269                        goto startParseArray;
     270                    case TokLBrace:
     271                        goto startParseObject;
     272                    case TokString: {
     273                        Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
     274                        m_lexer.next();
     275                        lastValue = jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2));
     276                        break;
     277                    }
     278                    case TokNumber: {
     279                        Lexer::LiteralParserToken numberToken = m_lexer.currentToken();
     280                        m_lexer.next();
     281                        lastValue = jsNumber(m_exec, UString(numberToken.start, numberToken.end - numberToken.start).toDouble());
     282                        break;
     283                    }
     284                    default:
     285                        // Error
     286                        return JSValue();
     287                }
     288                break;
     289            }
     290            case StartParseStatement: {
     291                switch (m_lexer.currentToken().type) {
     292                    case TokLBracket:
     293                    case TokNumber:
     294                    case TokString:
     295                        goto startParseExpression;
     296
     297                    case TokLParen: {
     298                        m_lexer.next();
     299                        stateStack.append(StartParseStatementEndStatement);
     300                        goto startParseExpression;
     301                    }
     302                    default:
     303                        return JSValue();
     304                }
     305            }
     306            case StartParseStatementEndStatement: {
     307                ASSERT(stateStack.isEmpty());
     308                if (m_lexer.currentToken().type != TokRParen)
     309                    return JSValue();
     310                if (m_lexer.next() == TokEnd)
     311                    return lastValue;
     312                return JSValue();
     313            }
     314            default:
     315                ASSERT_NOT_REACHED();
    218316        }
    219         default:
    220             return abortParse();
    221     }
    222 }
    223 
    224 JSValue LiteralParser::parseExpression()
    225 {
    226     StackGuard guard(this);
    227     if (!guard.isSafe())
    228         return abortParse();
    229     switch (m_lexer.currentToken().type) {
    230         case TokLBracket:
    231             return parseArray();
    232         case TokLBrace:
    233             return parseObject();
    234         case TokString: {
    235             Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
    236             m_lexer.next();
    237             return jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2));
    238         }
    239         case TokNumber: {
    240             Lexer::LiteralParserToken numberToken = m_lexer.currentToken();
    241             m_lexer.next();
    242             return jsNumber(m_exec, UString(numberToken.start, numberToken.end - numberToken.start).toDouble());
    243         }
    244         default:
    245             return JSValue();
    246     }
    247 }
    248 
    249 JSValue LiteralParser::parseArray()
    250 {
    251     StackGuard guard(this);
    252     if (!guard.isSafe())
    253         return abortParse();
    254     JSArray* array = constructEmptyArray(m_exec);
    255     while (true) {
    256         m_lexer.next();
    257         JSValue value = parseExpression();
    258         if (m_aborted)
    259             return JSValue();
    260         if (!value)
    261             break;
    262         array->push(m_exec, value);
    263 
    264         if (m_lexer.currentToken().type != TokComma)
    265             break;
    266     }
    267     if (m_lexer.currentToken().type != TokRBracket)
    268         return abortParse();
    269 
    270     m_lexer.next();
    271     return array;
    272 }
    273 
    274 JSValue LiteralParser::parseObject()
    275 {
    276     StackGuard guard(this);
    277     if (!guard.isSafe())
    278         return abortParse();
    279     JSObject* object = constructEmptyObject(m_exec);
    280    
    281     while (m_lexer.next() == TokString) {
    282         Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
    283        
    284         // Check for colon
    285         if (m_lexer.next() != TokColon)
    286             return abortParse();
    287         m_lexer.next();
    288        
    289         JSValue value = parseExpression();
    290         if (!value || m_aborted)
    291             return abortParse();
    292        
    293         Identifier ident(m_exec, identifierToken.start + 1, identifierToken.end - identifierToken.start - 2);
    294         object->putDirect(ident, value);
    295        
    296         if (m_lexer.currentToken().type != TokComma)
    297             break;
    298     }
    299    
    300     if (m_lexer.currentToken().type != TokRBrace)
    301         return abortParse();
    302     m_lexer.next();
    303     return object;
    304 }
    305 
    306 }
     317        if (stateStack.isEmpty())
     318            return lastValue;
     319        state = stateStack.last();
     320        stateStack.removeLast();
     321        continue;
     322    }
     323}
     324
     325}
Note: See TracChangeset for help on using the changeset viewer.