Variant xdebug_get_php_symbol(ActRec* ar, StringData* name) { int state; auto slice = name->slice(); const char *p = slice.begin(); const char *end = slice.end(); const char *keyword = nullptr; const char *keyword_end = nullptr; Class* ctx = nullptr; Variant sym; String key(name->size(), ReserveStringMode()); char quotechar = 0; SymbolType type = SymbolType::Root; StringData* sd = key.get(); char* keyBuf = sd->mutableData(); for (; p != end; ++p) { switch (state) { case 0: if (*p == '$') { keyword = p + 1; break; } // special tricks if (*p == ':') { keyword = p; state = 7; break; } keyword = p; state = 1; // fallthrough case 1: if (*p == '[') { keyword_end = p; if (keyword) { memcpy(keyBuf, keyword, keyword_end - keyword); sd->setSize(keyword_end - keyword); sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); ctx = nullptr; keyword = nullptr; } state = 3; } else if (*p == '-') { keyword_end = p; if (keyword) { memcpy(keyBuf, keyword, keyword_end - keyword); sd->setSize(keyword_end - keyword); sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); ctx = xdebug_get_sym_class(sym); keyword = nullptr; } state = 2; type = SymbolType::ObjProp; } else if (*p == ':') { keyword_end = p; if (keyword) { memcpy(keyBuf, keyword, keyword_end - keyword); sd->setSize(keyword_end - keyword); // XXX: this call is going to set ctx sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); keyword = nullptr; } state = 8; type = SymbolType::StaticProp; } break; case 2: if (*p != '>') { keyword = p; state = 1; } break; case 8: if (*p != ':') { keyword = p; state = 1; } break; // Parsing in [...] case 3: // Associative arrays if (*p == '\'' || *p == '"') { state = 4; keyword = p + 1; quotechar = *p; type = SymbolType::ArrayIndexAssoc; } // Numerical index if (*p >= '0' && *p <= '9') { state = 6; keyword = p; type = SymbolType::ArrayIndexNum; } // Numerical index starting with a - if (*p == '-') { state = 9; keyword = p; } break; // Numerical index starting with a - case 9: if (*p >= '0' && *p <= '9') { state = 6; type = SymbolType::ArrayIndexNum; } break; case 4: if (*p == quotechar) { quotechar = 0; state = 5; keyword_end = p; memcpy(keyBuf, keyword, keyword_end - keyword); sd->setSize(keyword_end - keyword); sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); ctx = xdebug_get_sym_class(sym); keyword = nullptr; } break; case 5: if (*p == ']') { state = 1; } break; case 6: if (*p == ']') { state = 1; keyword_end = p; memcpy(keyBuf, keyword, keyword_end - keyword); sd->setSize(keyword_end - keyword); sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); ctx = xdebug_get_sym_class(sym); keyword = nullptr; } break; // special cases, started with a ":" case 7: if (*p == ':') { state = 1; keyword_end = p; // static class properties if (keyword_end + 1 != end && strncmp(keyword, "::", 2) == 0) { ctx = ar->hasClass() ? ar->getClass() : ar->hasThis() ? ar->getThis()->getVMClass() : nullptr; sym = uninit_null(); keyword = p + 1; type = SymbolType::StaticRoot; } else { keyword = nullptr; } } break; } } if (keyword) { memcpy(keyBuf, keyword, p - keyword); sd->setSize(p - keyword); sym = xdebug_lookup_symbol(type, key, ctx, sym, ar); } return sym; }