void XMLBuffer::Parse() { m_elements.clear(); CHECK_PTR_RET(m_scanner); XMLLexerToken token; m_state = kNormal; while(::xmlLexerNext(m_scanner, token)) { switch(token.type) { case kXML_T_CDATA_START: m_state = kCdata; if(ConsumeUntil(kXML_T_CDATA_END)) { m_state = kNormal; } break; case kXML_T_COMMENT_START: m_state = kComment; if(ConsumeUntil(kXML_T_COMMENT_END)) { m_state = kNormal; } break; case '<': // "<" was found OnOpenTag(); break; case '>': // ">" was found. If in HTML mode and the current scope is an open tag // pop it OnCloseTag(); break; case kXML_T_CLOSE_TAG_PREFIX: // "</" was found OnTagClosePrefix(); break; case kXML_T_CLOSE_TAG_SUFFIX: // "/>" closing tag was found if(!m_elements.empty()) m_elements.pop_back(); break; default: break; } } }
void PHPSourceFile::OnDefine(const phpLexerToken& tok) { phpLexerToken token; if(!NextToken(token)) return; // EOF if(token.type != '(') { ConsumeUntil(';'); return; } if(!NextToken(token)) return; // EOF if(token.type != kPHP_T_CONSTANT_ENCAPSED_STRING) { ConsumeUntil(';'); return; } // Remove the quotes wxString varName = token.text; if((varName.StartsWith("\"") && varName.EndsWith("\"")) || (varName.StartsWith("'") && varName.EndsWith("'"))) { varName.Remove(0, 1); varName.RemoveLast(); // define() defines constants exactly as it was instructed // i.e. it does not take the current namespace into consideration PHPEntityBase::Ptr_t var(new PHPEntityVariable()); // Convert the variable into fullpath + relative name if(!varName.StartsWith("\\")) { varName.Prepend("\\"); } wxString shortName = varName.AfterLast('\\'); var->SetFullName(varName); var->SetShortName(shortName); var->SetFlag(kVar_Define); var->SetFilename(GetFilename()); var->SetLine(tok.lineNumber); // We keep the defines in a special list // this is because 'define' does not obay to the current scope m_defines.push_back(var); } // Always consume the 'define' statement ConsumeUntil(';'); }
void PHPSourceFile::Parse(int exitDepth) { int retDepth = exitDepth; phpLexerToken token; while(NextToken(token)) { switch(token.type) { case '=': m_lookBackTokens.clear(); break; case '{': m_lookBackTokens.clear(); break; case '}': m_lookBackTokens.clear(); if(m_depth == retDepth) { return; } break; case ';': m_lookBackTokens.clear(); break; case kPHP_T_VARIABLE: if(!CurrentScope()->Is(kEntityTypeClass)) { // A global variable OnVariable(token); } break; case kPHP_T_CATCH: // found 'catch (...)' OnCatch(); break; case kPHP_T_PUBLIC: case kPHP_T_PRIVATE: case kPHP_T_PROTECTED: { int visibility = token.type; PHPEntityClass* cls = CurrentScope()->Cast<PHPEntityClass>(); if(cls) { /// keep the current token m_lookBackTokens.push_back(token); // Now we have a small problem here: // public can be a start for a member or a function // we let the lexer run forward until it finds kPHP_T_VARIABLE (for variable) // or kPHP_T_IDENTIFIER int what = ReadUntilFoundOneOf(kPHP_T_VARIABLE, kPHP_T_FUNCTION, token); if(what == kPHP_T_VARIABLE) { // A variable PHPEntityBase::Ptr_t member(new PHPEntityVariable()); member->SetFilename(m_filename.GetFullPath()); member->Cast<PHPEntityVariable>()->SetVisibility(visibility); member->Cast<PHPEntityVariable>()->SetFullName(token.text); size_t flags = LookBackForVariablesFlags(); member->Cast<PHPEntityVariable>()->SetFlag(kVar_Member); member->Cast<PHPEntityVariable>()->SetFlag(kVar_Const, flags & kVar_Const); member->Cast<PHPEntityVariable>()->SetFlag(kVar_Static, flags & kVar_Static); member->Cast<PHPEntityVariable>()->SetLine(token.lineNumber); CurrentScope()->AddChild(member); // Handle member assignment // public $memberVar = new Something(); // for such cases, assign $memberVar type of Something() phpLexerToken t; if(!NextToken(t)) { // EOF return; } if(t.type == '=') { // assignment wxString expr; if(!ReadExpression(expr)) { return; } // Optimize 'new ClassName(..)' expression if(expr.StartsWith("new")) { expr = expr.Mid(3); expr.Trim().Trim(false); expr = expr.BeforeFirst('('); expr.Trim().Trim(false); member->Cast<PHPEntityVariable>()->SetTypeHint(MakeIdentifierAbsolute(expr)); } else { // keep the expression member->Cast<PHPEntityVariable>()->SetExpressionHint(expr); } } else { // restore the token UngetToken(t); if(!ConsumeUntil(';')) return; } } else if(what == kPHP_T_FUNCTION) { // A function... OnFunction(); m_lookBackTokens.clear(); } } break; } case kPHP_T_DEFINE: // Define statement OnDefine(token); break; case kPHP_T_CONST: OnConstant(token); break; case kPHP_T_REQUIRE: case kPHP_T_REQUIRE_ONCE: case kPHP_T_INCLUDE: case kPHP_T_INCLUDE_ONCE: // Handle include files m_lookBackTokens.clear(); break; case kPHP_T_FOREACH: // found "foreach" statement OnForEach(); m_lookBackTokens.clear(); break; case kPHP_T_USE: // Found outer 'use' statement - construct the alias table if(Class()) { // inside a class, this means that this is a 'use <trait>;' OnUseTrait(); } else { // alias table OnUse(); } m_lookBackTokens.clear(); break; case kPHP_T_CLASS: case kPHP_T_INTERFACE: case kPHP_T_TRAIT: // Found class OnClass(token); m_lookBackTokens.clear(); break; case kPHP_T_NAMESPACE: // Found a namespace OnNamespace(); m_lookBackTokens.clear(); break; case kPHP_T_FUNCTION: // Found function OnFunction(); m_lookBackTokens.clear(); break; default: // Keep the token break; } } PhaseTwo(); }
void PHPSourceFile::OnFunction() { // read the next token phpLexerToken token; if(!NextToken(token)) { return; } bool funcReturnRef = false; if(token.type == '&') { funcReturnRef = true; if(!NextToken(token)) { return; } } PHPEntityFunction* func(NULL); int funcDepth(0); if(token.type == kPHP_T_IDENTIFIER) { // the function name func = new PHPEntityFunction(); func->SetFullName(token.text); func->SetLine(token.lineNumber); } else if(token.type == '(') { funcDepth = 1; // Since we already consumed the open brace // anonymous function func = new PHPEntityFunction(); func->SetLine(token.lineNumber); } if(!func) return; PHPEntityBase::Ptr_t funcPtr(func); if(funcReturnRef) { funcPtr->SetFlag(kFunc_ReturnReference); } // add the function to the current scope CurrentScope()->AddChild(funcPtr); // Set the function as the current scope m_scopes.push_back(funcPtr); // update function attributes ParseFunctionSignature(funcDepth); func->SetFlags(LookBackForFunctionFlags()); if(LookBackTokensContains(kPHP_T_ABSTRACT) || // The 'abstract modifier was found for this this function (funcPtr->Parent() && funcPtr->Parent()->Is(kEntityTypeClass) && funcPtr->Parent()->Cast<PHPEntityClass>()->IsInterface())) // We are inside an interface { // Mark this function as an abstract function func->SetFlags(func->GetFlags() | kFunc_Abstract); } if(func->HasFlag(kFunc_Abstract)) { // an abstract function - it has no body if(!ConsumeUntil(';')) { // could not locate the function delimiter, remove it from the stack // we probably reached EOF here m_scopes.pop_back(); } } else { if(!NextToken(token)) return; if(token.type == ':') { // PHP 7 signature type // function foobar(...) : RETURN_TYPE wxString returnValuetype = ReadType(); if(returnValuetype.IsEmpty()) return; // parse error func->SetReturnValue(returnValuetype); } else { // untake the token and place it back on the "unget" list UngetToken(token); } if(ReadUntilFound('{', token)) { // found the function body starting point if(IsParseFunctionBody()) { ParseFunctionBody(); } else { // Consume the function body ConsumeFunctionBody(); } } else { // could not locate the open brace! // remove this function from the stack m_scopes.pop_back(); } } // Remove the current function from the scope list if(!m_reachedEOF) { m_scopes.pop_back(); } m_lookBackTokens.clear(); }
void PHPSourceFile::ParseUseTraitsBody() { wxString fullname, alias, temp; phpLexerToken token; bool cont = true; while(cont && NextToken(token)) { switch(token.type) { case '}': { cont = false; } break; case ',': case ';': { if(fullname.IsEmpty()) { // no full name yet fullname.swap(temp); } else if(alias.IsEmpty()) { alias.swap(temp); } if(alias.IsEmpty()) { // no alias provided, use the last part of the fullname alias = fullname.AfterLast('\\'); } if(!fullname.IsEmpty() && !alias.IsEmpty()) { // Use namespace is alway refered as fullpath namespace // So writing: // use Zend\Mvc\Controll\Action; // is equal for writing: // use \Zend\Mvc\Controll\Action; // For simplicitiy, we change it to fully qualified path // so parsing is easier if(!fullname.StartsWith("\\")) { fullname.Prepend("\\"); } PHPEntityBase::Ptr_t funcAlias(new PHPEntityFunctionAlias()); funcAlias->Cast<PHPEntityFunctionAlias>()->SetRealname(MakeIdentifierAbsolute(fullname)); funcAlias->Cast<PHPEntityFunctionAlias>()->SetScope(CurrentScope()->GetFullName()); funcAlias->SetShortName(alias); funcAlias->SetFullName(CurrentScope()->GetFullName() + "\\" + alias); funcAlias->SetFilename(GetFilename()); funcAlias->SetLine(token.lineNumber); CurrentScope()->AddChild(funcAlias); } temp.clear(); fullname.clear(); alias.clear(); } break; case kPHP_T_PAAMAYIM_NEKUDOTAYIM: { // Convert "::" into "\\" temp << "\\"; } break; case kPHP_T_AS: { fullname.swap(temp); temp.clear(); } break; case kPHP_T_INSTEADOF: { // For now, we are not interested in // A insteadof b; statements, so just clear the collected data so far fullname.clear(); temp.clear(); alias.clear(); if(!ConsumeUntil(';')) return; } break; default: temp << token.text; break; } } }
void PHPSourceFile::Parse(int exitDepth) { int retDepth = exitDepth; phpLexerToken token; while(NextToken(token)) { switch(token.type) { case '=': m_lookBackTokens.clear(); break; case '{': m_lookBackTokens.clear(); break; case '}': m_lookBackTokens.clear(); if(m_depth == retDepth) { return; } break; case ';': m_lookBackTokens.clear(); break; case kPHP_T_VARIABLE: if(!CurrentScope()->Is(kEntityTypeClass)) { // A global variable OnVariable(token); } break; case kPHP_T_CATCH: // found 'catch (...)' OnCatch(); break; case kPHP_T_PUBLIC: case kPHP_T_PRIVATE: case kPHP_T_PROTECTED: { int visibility = token.type; PHPEntityClass* cls = CurrentScope()->Cast<PHPEntityClass>(); if(cls) { /// keep the current token m_lookBackTokens.push_back(token); // Now we have a small problem here: // public can be a start for a member or a function // we let the lexer run forward until it finds kPHP_T_VARIABLE (for variable) // or kPHP_T_IDENTIFIER int what = ReadUntilFoundOneOf(kPHP_T_VARIABLE, kPHP_T_FUNCTION, token); if(what == kPHP_T_VARIABLE) { // A variable PHPEntityBase::Ptr_t member(new PHPEntityVariable()); member->SetFilename(m_filename.GetFullPath()); PHPEntityVariable* var = member->Cast<PHPEntityVariable>(); var->SetVisibility(visibility); var->SetFullName(token.text); size_t flags = LookBackForVariablesFlags(); var->SetFlag(kVar_Member); var->SetFlag(kVar_Const, flags & kVar_Const); var->SetFlag(kVar_Static, flags & kVar_Static); var->SetLine(token.lineNumber); CurrentScope()->AddChild(member); if(!ConsumeUntil(';')) return; } else if(what == kPHP_T_FUNCTION) { // A function... OnFunction(); m_lookBackTokens.clear(); } } break; } case kPHP_T_DEFINE: // Define statement OnDefine(token); break; case kPHP_T_CONST: if(ReadUntilFound(kPHP_T_IDENTIFIER, token)) { // constant PHPEntityBase::Ptr_t member(new PHPEntityVariable()); member->SetFilename(m_filename.GetFullPath()); PHPEntityVariable* var = member->Cast<PHPEntityVariable>(); var->SetFullName(token.text); var->SetLine(token.lineNumber); var->SetFlag(kVar_Member); var->SetFlag(kVar_Const); CurrentScope()->AddChild(member); if(!ConsumeUntil(';')) return; } break; case kPHP_T_REQUIRE: case kPHP_T_REQUIRE_ONCE: case kPHP_T_INCLUDE: case kPHP_T_INCLUDE_ONCE: // Handle include files m_lookBackTokens.clear(); break; case kPHP_T_USE: // Found outer 'use' statement - construct the alias table if(Class()) { // inside a class, this means that this is a 'use <trait>;' OnUseTrait(); } else { // alias table OnUse(); } m_lookBackTokens.clear(); break; case kPHP_T_CLASS: case kPHP_T_INTERFACE: case kPHP_T_TRAIT: // Found class OnClass(token); m_lookBackTokens.clear(); break; case kPHP_T_NAMESPACE: // Found a namespace OnNamespace(); m_lookBackTokens.clear(); break; case kPHP_T_FUNCTION: // Found function OnFunction(); m_lookBackTokens.clear(); break; default: // Keep the token break; } } PhaseTwo(); }