bool Scanner::tryParseTypeList(TokenStore::iterator& pos) { for (int parsed = 0;; parsed++) { if (pos->t == '+' || pos->t == '-') { nextLookahead(pos); } auto cpPos = pos; if (!tryParseNSType(cpPos)) { if (parsed > 0) { pos = cpPos; return true; } else { return false; } } pos = cpPos; while (pos->t == T_AS || pos->t == T_SUPER) { nextLookahead(pos); if (!tryParseNSType(pos)) { return false; } } if (pos->t != ',') return true; nextLookahead(pos); } }
bool Scanner::tryParseTypeList(TokenStore::iterator& pos) { for (;;) { if (!tryParseNSType(pos)) return false; if (pos->t == T_AS) { nextLookahead(pos); if (!tryParseNSType(pos)) return false; } if (pos->t != ',') return true; nextLookahead(pos); } }
bool Scanner::tryParseShapeMemberList(TokenStore::iterator& pos) { assert(pos->t != ')'); // already determined to be nonempty for (;;) { if (!nextIfToken(pos, T_CONSTANT_ENCAPSED_STRING) || !nextIfToken(pos, T_DOUBLE_ARROW)) { return false; } if (!tryParseNSType(pos)) return false; if (pos->t == ')') return true; if (!nextIfToken(pos, ',')) return false; if (pos->t == ')') return true; } return false; }
bool Scanner::tryParseFuncTypeList(TokenStore::iterator& pos) { for (int parsed = 0;;parsed++) { if (pos->t == T_ELLIPSIS) { nextLookahead(pos); return true; } auto cpPos = pos; if (!tryParseNSType(cpPos)) { if (parsed > 0) { pos = cpPos; return true; } else { return false; } } pos = cpPos; if (pos->t != ',') return true; nextLookahead(pos); } }
bool Scanner::tryParseNonEmptyLambdaParams(TokenStore::iterator& pos) { for (;; nextLookahead(pos)) { if (pos->t != T_VARIABLE) { if (pos->t == T_ELLIPSIS) { nextLookahead(pos); return true; } if (!tryParseNSType(pos)) return false; if (pos->t == '&') { nextLookahead(pos); } if (pos->t != T_VARIABLE) return false; } nextLookahead(pos); if (pos->t == '=') { nextLookahead(pos); parseApproxParamDefVal(pos); } if (pos->t != ',') return true; } }
int Scanner::getNextToken(ScannerToken &t, Location &l) { int tokid; bool la = !m_lookahead.empty(); tokid = fetchToken(t, l); if (LIKELY(!isUnresolved(tokid))) { // In the common case, we don't have to perform any resolution // and we can just return the token if (UNLIKELY(la)) { // If we pulled a lookahead token, we need to remove it from // the lookahead store m_lookahead.popFront(); } return tokid; } if (!la) { // If this token didn't come from the lookahead store, we // need to stash it there TokenStore::iterator it = m_lookahead.appendNew(); LookaheadToken ltd = { t, l, tokid }; *it = ltd; } switch (tokid) { case T_UNRESOLVED_NEWTYPE: case T_UNRESOLVED_TYPE: { auto pos = m_lookahead.begin(); auto typePos = pos; nextLookahead(pos); if (isValidClassConstantName(pos->t)) { typePos->t = tokid == T_UNRESOLVED_TYPE ? T_TYPE : T_NEWTYPE; } else { typePos->t = T_STRING; } break; } case T_UNRESOLVED_LT: { // Look at subsequent tokens to determine if the '<' character // is the start of a type list auto pos = m_lookahead.begin(); auto ltPos = pos; nextLookahead(pos); ++m_lookaheadLtDepth; bool isTypeList = tryParseTypeList(pos); --m_lookaheadLtDepth; if (isTypeList && pos->t == '>') { ltPos->t = T_TYPELIST_LT; pos->t = T_TYPELIST_GT; } else { ltPos->t = '<'; } break; } case T_UNRESOLVED_OP: { // Look at subsequent tokens to determine if the '(' character // is the start of a lambda expression auto pos = m_lookahead.begin(); auto opPos = pos; nextLookahead(pos); if (pos->t != ')' && pos->t != T_LAMBDA_CP) { if (!tryParseNonEmptyLambdaParams(pos) || pos->t != ')') { opPos->t = '('; break; } } auto cpPos = pos; nextLookahead(pos); if (pos->t == ':') { nextLookahead(pos); if (!tryParseNSType(pos)) { opPos->t = '('; break; } } if (pos->t == T_LAMBDA_ARROW) { opPos->t = T_LAMBDA_OP; cpPos->t = T_LAMBDA_CP; } else { opPos->t = '('; } break; } default: always_assert(0); } tokid = fetchToken(t, l); // We pulled a lookahead token, we need to remove it from the // lookahead store m_lookahead.popFront(); return tokid; }
bool Scanner::tryParseNSType(TokenStore::iterator& pos) { if (pos->t == '@') { nextLookahead(pos); } if (pos->t == '?') { nextLookahead(pos); } if (pos->t == '(' || pos->t == T_UNRESOLVED_OP) { nextLookahead(pos); if (pos->t == T_FUNCTION) { nextLookahead(pos); if (pos->t != '(') return false; nextLookahead(pos); if (pos->t != ')') { if (!tryParseFuncTypeList(pos)) return false; if (pos->t != ')') return false; } nextLookahead(pos); if (pos->t == ')') { nextLookahead(pos); return true; } if (pos->t != ':') return false; nextLookahead(pos); if (!tryParseNSType(pos)) return false; if (pos->t != ')') return false; nextLookahead(pos); return true; } if (!tryParseTypeList(pos)) return false; if (pos->t != ')') return false; nextLookahead(pos); return true; } if (pos->t == T_NAMESPACE) { nextLookahead(pos); if (pos->t != T_NS_SEPARATOR) return false; nextLookahead(pos); } else if (pos->t == T_NS_SEPARATOR) { nextLookahead(pos); } for (;;) { switch (pos->t) { case T_STRING: case T_SUPER: case T_XHP_ATTRIBUTE: case T_XHP_CATEGORY: case T_XHP_CHILDREN: case T_XHP_REQUIRED: case T_ENUM: case T_ARRAY: case T_CALLABLE: case T_UNRESOLVED_TYPE: case T_UNRESOLVED_NEWTYPE: nextLookahead(pos); break; case T_SHAPE: return tryParseShapeType(pos); case T_XHP_LABEL: nextLookahead(pos); return true; default: return false; } if (pos->t == T_UNRESOLVED_LT) { TokenStore::iterator ltPos = pos; nextLookahead(pos); ++m_lookaheadLtDepth; bool isTypeList = tryParseTypeList(pos); --m_lookaheadLtDepth; if (!isTypeList || pos->t != '>') { ltPos->t = '<'; return false; } ltPos->t = T_TYPELIST_LT; pos->t = T_TYPELIST_GT; nextLookahead(pos); return true; } if (pos->t != T_NS_SEPARATOR && pos->t != T_DOUBLE_COLON) { return true; } nextLookahead(pos); } }