Exemplo n.º 1
0
/*foreach (array_expression as $value)
    statement
foreach (array_expression as $key => $value)
    statement*/
void PHPSourceFile::OnForEach()
{
    // read until the "as" keyword
    phpLexerToken token;
    if(!ReadUntilFound(kPHP_T_AS, token)) return;

    // Found the "as" key word and consumed it
    if(!NextToken(token)) return;

    phpLexerToken peekToken;
    if(!NextToken(peekToken)) return;

    // Ensure we got a variable
    if(token.type != kPHP_T_VARIABLE) return;

    // Check to see if we are using the syntax of:
    // foreach (array_expression as $key => $value)
    if(peekToken.type == kPHP_T_DOUBLE_ARROW) {
        if(!NextToken(token) || token.type != kPHP_T_VARIABLE) {
            return;
        }
    } else {
        UngetToken(peekToken);
    }

    // Create a new variable
    PHPEntityBase::Ptr_t var(new PHPEntityVariable());
    var->SetFullName(token.text);
    var->SetFilename(m_filename.GetFullPath());
    var->SetLine(token.lineNumber);

    if(!CurrentScope()->FindChild(var->GetFullName(), true)) {
        CurrentScope()->AddChild(var);
    }
}
Exemplo n.º 2
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;
        }
    }
}
Exemplo n.º 3
0
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();
}
Exemplo n.º 4
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());
                    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();
}