Ejemplo n.º 1
0
void PHPSourceFile::ReadImplements(wxArrayString& impls)
{
    wxString type;
    phpLexerToken token;
    while(NextToken(token)) {
        switch(token.type) {
        case kPHP_T_IDENTIFIER:
        case kPHP_T_NS_SEPARATOR:
            type << token.text;
            break;
        case ',':
            // More to come
            if(!type.IsEmpty()) {
                wxString fullyQualifiedType = MakeIdentifierAbsolute(type);
                if(impls.Index(fullyQualifiedType) == wxNOT_FOUND) {
                    impls.Add(fullyQualifiedType);
                }
                type.clear();
            }
            break;
        default:
            // unexpected token
            if(!type.IsEmpty()) {
                wxString fullyQualifiedType = MakeIdentifierAbsolute(type);
                if(impls.Index(fullyQualifiedType) == wxNOT_FOUND) {
                    impls.Add(fullyQualifiedType);
                }
                type.clear();
            }
            UngetToken(token);
            return;
        }
    }
}
Ejemplo n.º 2
0
bool PHPSourceFile::ReadCommaSeparatedIdentifiers(int delim, wxArrayString& list)
{
    phpLexerToken token;
    wxString temp;
    while(NextToken(token)) {
        if(token.IsAnyComment()) continue;
        if(token.type == delim) {
            if(!temp.IsEmpty() && list.Index(temp) == wxNOT_FOUND) {
                list.Add(MakeIdentifierAbsolute(temp));
            }
            UngetToken(token);
            return true;
        }

        switch(token.type) {
        case ',':
            if(list.Index(temp) == wxNOT_FOUND) {
                list.Add(MakeIdentifierAbsolute(temp));
            }
            temp.clear();
            break;
        default:
            temp << token.text;
            break;
        }
    }
    return false;
}
Ejemplo n.º 3
0
void PHPSourceFile::OnUseTrait()
{
    PHPEntityBase::Ptr_t clas = CurrentScope();
    if(!clas) return;

    // Collect the identifiers followed the 'use' statement
    wxArrayString identifiers;
    wxString tempname;
    phpLexerToken token;
    while(NextToken(token)) {
        switch(token.type) {
        case ',': {
            if(!tempname.IsEmpty()) {
                identifiers.Add(MakeIdentifierAbsolute(tempname));
            }
            tempname.clear();
        } break;
        case ';': {
            if(!tempname.IsEmpty()) {
                identifiers.Add(MakeIdentifierAbsolute(tempname));
            }
            tempname.clear();

            // add the traits as list of 'extends'
            clas->Cast<PHPEntityClass>()->SetTraits(identifiers);
            return;
        } break;
        default:
            tempname << token.text;
            break;
        }
    }
}
Ejemplo n.º 4
0
void PHPSourceFile::OnClass(const phpLexerToken& tok)
{
    // A "complex" example: class A extends BaseClass implements C, D {}

    // Read until we get the class name
    phpLexerToken token;
    while(NextToken(token)) {
        if(token.IsAnyComment()) continue;
        if(token.type != kPHP_T_IDENTIFIER) {
            // expecting the class name
            return;
        }
        break;
    }

    // create new class entity
    PHPEntityBase::Ptr_t klass(new PHPEntityClass());
    klass->SetFilename(m_filename.GetFullPath());
    PHPEntityClass* pClass = klass->Cast<PHPEntityClass>();
    // Is the class an interface?
    pClass->SetIsInterface(tok.type == kPHP_T_INTERFACE);
    pClass->SetIsTrait(tok.type == kPHP_T_TRAIT);
    pClass->SetFullName(MakeIdentifierAbsolute(token.text));
    pClass->SetLine(token.lineNumber);

    while(NextToken(token)) {
        if(token.IsAnyComment()) continue;
        switch(token.type) {
        case kPHP_T_EXTENDS: {
            // inheritance
            if(!ReadUntilFound(kPHP_T_IDENTIFIER, token)) return;
            pClass->SetExtends(MakeIdentifierAbsolute(token.text));
        } break;
        case kPHP_T_IMPLEMENTS: {
            wxArrayString implements;
            if(!ReadCommaSeparatedIdentifiers('{', implements)) return;
            pClass->SetImplements(implements);

        } break;
        case '{': {
            // entering the class body
            // add the current class to the current scope
            CurrentScope()->AddChild(klass);
            m_scopes.push_back(klass);
            Parse(m_depth - 1);
            if(!m_reachedEOF) {
                m_scopes.pop_back();
            }
            return;
        }
        default:
            break;
        }
    }
}
Ejemplo n.º 5
0
wxString PHPSourceFile::ReadType()
{
    bool cont = true;
    wxString type;
    phpLexerToken token;

    while(cont && NextToken(token)) {
        switch(token.type) {
        case kPHP_T_IDENTIFIER:
            type << token.text;
            break;

        case kPHP_T_NS_SEPARATOR:
            type << token.text;
            break;
        default:
            // restore the token so next call to NextToken
            // will pick it up again
            UngetToken(token);
            cont = false;
            break;
        }
    }

    type = MakeIdentifierAbsolute(type);
    return type;
}
Ejemplo n.º 6
0
bool PHPSourceFile::ReadVariableInitialization(PHPEntityBase::Ptr_t var)
{
    phpLexerToken token;
    if(!NextToken(token)) {
        return false;
    }

    if(token.type != '=') {
        // restore the token
        UngetToken(token);
        return false;
    }

    wxString expr;
    if(!ReadExpression(expr)) {
        return false; // EOF
    }

    // Optimize 'new ClassName(..)' expression
    if(expr.StartsWith("new")) {
        expr = expr.Mid(3);
        expr.Trim().Trim(false);
        expr = expr.BeforeFirst('(');
        expr.Trim().Trim(false);
        var->Cast<PHPEntityVariable>()->SetTypeHint(MakeIdentifierAbsolute(expr));

    } else {
        // keep the expression
        var->Cast<PHPEntityVariable>()->SetExpressionHint(expr);
    }
    return true;
}
Ejemplo n.º 7
0
wxString PHPSourceFile::ReadType()
{
    bool cont = true;
    wxString type;
    phpLexerToken token;
    while(cont && NextToken(token)) {
        switch(token.type) {
        case kPHP_T_IDENTIFIER:
            type << token.text;
            break;

        case kPHP_T_NS_SEPARATOR:
            type << token.text;
            break;

        // special cases that must always be handled
        case '{':
            cont = false;
            break;
        // end of special cases
        default:
            cont = false;
            break;
        }
    }
    type = MakeIdentifierAbsolute(type);
    return type;
}
Ejemplo n.º 8
0
void PHPSourceFile::OnUse()
{
    wxString fullname, alias, temp;
    phpLexerToken token;
    bool cont = true;
    while(cont && NextToken(token)) {
        switch(token.type) {
        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("\\");
                }
                m_aliases.insert(std::make_pair(alias, MakeIdentifierAbsolute(fullname)));
            }
            temp.clear();
            fullname.clear();
            alias.clear();
            if(token.type == ';') {
                cont = false;
            }
        } break;
        case kPHP_T_AS: {
            fullname.swap(temp);
            temp.clear();
        } break;
        default:
            temp << token.text;
            break;
        }
    }
}
Ejemplo n.º 9
0
wxString PHPSourceFile::ReadExtends()
{
    wxString type;
    phpLexerToken token;
    while(NextToken(token)) {
        if(token.type == kPHP_T_IDENTIFIER || token.type == kPHP_T_NS_SEPARATOR) {
            type << token.text;
        } else {
            UngetToken(token);
            break;
        }
    }
    type = MakeIdentifierAbsolute(type);
    return type;
}
Ejemplo n.º 10
0
void PHPSourceFile::OnCatch()
{
    // Read until we find the kPHP_T_VARIABLE
    bool cont(true);
    phpLexerToken token;
    wxString typehint;
    wxString varname;
    while(cont && NextToken(token)) {
        switch(token.type) {
        case kPHP_T_VARIABLE:
            cont = false;
            varname = token.text;
            break;
        case kPHP_T_IDENTIFIER:
        case kPHP_T_NS_SEPARATOR:
            typehint << token.text;
            break;
        default:
            break;
        }
    }

    if(!varname.IsEmpty()) {
        // we found the variable
        PHPEntityBase::Ptr_t var(new PHPEntityVariable());
        var->SetFullName(varname);
        var->SetFilename(m_filename.GetFullPath());
        var->SetLine(token.lineNumber);
        var->Cast<PHPEntityVariable>()->SetTypeHint(MakeIdentifierAbsolute(typehint));

        // add the variable to the current scope
        if(!CurrentScope()->FindChild(var->GetFullName(), true)) {
            CurrentScope()->AddChild(var);
        }
    }
}
Ejemplo n.º 11
0
void PHPSourceFile::OnVariable(const phpLexerToken& tok)
{
    phpLexerToken token;
    // Read until we find the ';'
    std::vector<phpLexerToken> tokens;
    PHPEntityBase::Ptr_t var(new PHPEntityVariable());
    var->SetFullName(tok.text);
    var->SetFilename(m_filename.GetFullPath());
    var->SetLine(tok.lineNumber);
    if(!CurrentScope()->FindChild(var->GetFullName(), true)) {
        CurrentScope()->AddChild(var);
    }

    if(!NextToken(token)) return;

    if(token.type != '=') {
        m_lookBackTokens.clear();
        return;
    }

    wxString expr;
    if(!ReadExpression(expr)) return; // EOF

    // Optimize 'new ClassName(..)' expression
    if(expr.StartsWith("new")) {
        expr = expr.Mid(3);
        expr.Trim().Trim(false);
        expr = expr.BeforeFirst('(');
        expr.Trim().Trim(false);
        var->Cast<PHPEntityVariable>()->SetTypeHint(MakeIdentifierAbsolute(expr));

    } else {
        // keep the expression
        var->Cast<PHPEntityVariable>()->SetExpressionHint(expr);
    }
}
Ejemplo n.º 12
0
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();
}
Ejemplo n.º 13
0
void PHPSourceFile::ParseFunctionBody()
{
    m_lookBackTokens.clear();

    // when we reach the current depth-1 -> leave
    int exitDepth = m_depth - 1;
    phpLexerToken token;
    PHPEntityBase::Ptr_t var(NULL);
    while(NextToken(token)) {
        switch(token.type) {
        case '{':
            m_lookBackTokens.clear();
            break;
        case '}':
            m_lookBackTokens.clear();
            if(m_depth == exitDepth) {
                return;
            }
            break;
        case ';':
            m_lookBackTokens.clear();
            break;
        case kPHP_T_CATCH:
            OnCatch();
            break;
        case kPHP_T_VARIABLE: {
            var.Reset(new PHPEntityVariable());
            var->SetFullName(token.text);
            var->SetFilename(m_filename.GetFullPath());
            var->SetLine(token.lineNumber);
            CurrentScope()->AddChild(var);

            // Peek at the next token
            if(!NextToken(token)) return; // EOF
            if(token.type != '=') {
                m_lookBackTokens.clear();
                var.Reset(NULL);
                UngetToken(token);

            } else {

                wxString expr;
                if(!ReadExpression(expr)) return; // EOF

                // Optimize 'new ClassName(..)' expression
                if(expr.StartsWith("new")) {
                    expr = expr.Mid(3);
                    expr.Trim().Trim(false);
                    expr = expr.BeforeFirst('(');
                    expr.Trim().Trim(false);
                    var->Cast<PHPEntityVariable>()->SetTypeHint(MakeIdentifierAbsolute(expr));

                } else {
                    // keep the expression
                    var->Cast<PHPEntityVariable>()->SetExpressionHint(expr);
                }
            }
        } break;
        default:
            break;
        }
    }
}
Ejemplo n.º 14
0
void PHPSourceFile::ParseFunctionSignature(int startingDepth)
{
    phpLexerToken token;
    if(startingDepth == 0) {
        // loop until we find the open brace
        while(NextToken(token)) {
            if(token.type == '(') {
                ++startingDepth;
                break;
            }
        }
        if(startingDepth == 0) return;
    }

    // at this point the 'depth' is 1, as we already read the open brace
    int depth = 1;
    wxString typeHint;
    wxString defaultValue;
    PHPEntityVariable* var(NULL);
    bool collectingDefaultValue = false;
    while(NextToken(token)) {
        switch(token.type) {
        case kPHP_T_VARIABLE:
            if(!var) {
                // var can be non null if we are parsing PHP-7 function arguments
                // with type-hinting
                var = new PHPEntityVariable();
            }

            var->SetFullName(token.text);
            var->SetLine(token.lineNumber);
            var->SetFilename(m_filename);
            // Mark this variable as function argument
            var->SetFlag(kVar_FunctionArg);
            if(typeHint.EndsWith("&")) {
                var->SetIsReference(true);
                typeHint.RemoveLast();
            }
            var->SetTypeHint(MakeIdentifierAbsolute(typeHint));
            break;
        case '(':
            depth++;
            if(collectingDefaultValue) {
                defaultValue << "(";
            }
            break;
        case ')':
            depth--;
            // if the depth goes under 1 - we are done
            if(depth < 1) {
                if(var) {
                    var->SetDefaultValue(defaultValue);
                    CurrentScope()->AddChild(PHPEntityBase::Ptr_t(var));
                }
                return;

            } else if(depth) {
                defaultValue << token.text;
            }
            break;
        case '=':
            // default value
            collectingDefaultValue = true;
            break;
        case ',':
            if(var) {
                var->SetDefaultValue(defaultValue);
                CurrentScope()->AddChild(PHPEntityBase::Ptr_t(var));
            }
            var = NULL;
            typeHint.Clear();
            defaultValue.Clear();
            collectingDefaultValue = false;
            break;
        case kPHP_T_IDENTIFIER:
            if(!var) {
                // PHP-7 type hinting function arguments
                var = new PHPEntityVariable();
                UngetToken(token);
                typeHint = ReadType();
                if(!typeHint.IsEmpty()) {
                    break;
                }
            }
        // all "else" cases simply fall into the default case
        default:
            if(collectingDefaultValue) {
                defaultValue << token.text;
            } else {
                typeHint << token.text;
            }
            break;
        }
    }
}
Ejemplo n.º 15
0
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;
        }
    }
}