Exemplo n.º 1
0
        private void ParseSrc(FileModel fileModel, string ba)
        {
            model = fileModel;
            if (model.haXe)
            {
                model.Enums.Clear();
            }
            model.Classes.Clear();
            model.Members.Clear();

            // state
            int len = ba.Length;

            if (len < 0)
            {
                return;
            }
            int i    = 0;
            int line = 0;

            // when parsing cache file including multiple files
resetParser:

            char c1;
            char c2;
            int  matching   = 0;
            bool isInString = false;
            int  inString   = 0;
            int  braceCount = 0;
            bool inCode     = true;

            // comments
            char[] commentBuffer = new char[COMMENTS_BUFFER];
            int    commentLength = 0;

            lastComment = null;
            curComment  = null;

            // tokenisation
            tryPackage = true;
            haXe       = model.haXe;
            version    = (haXe)? 4 : 1;
            curToken   = new Token();
            prevToken  = new Token();
            int tokPos  = 0;
            int tokLine = 0;

            curMethod    = null;
            curMember    = null;
            valueKeyword = null;
            curModifiers = 0;
            curNamespace = "public";

            char[] buffer = new char[TOKEN_BUFFER];
            int    length = 0;

            char[] valueBuffer     = new char[VALUE_BUFFER];
            int    valueLength     = 0;
            int    paramBraceCount = 0;
            int    paramTempCount  = 0;
            int    paramParCount   = 0;
            int    paramSqCount    = 0;

            bool hadWS  = true;
            bool hadDot = false;

            inParams = false;
            inEnum   = false;
            inValue  = false;
            inType   = false;

            bool addChar     = false;
            int  evalToken   = 0;
            bool evalKeyword = true;

            context    = 0;
            modifiers  = 0;
            foundColon = false;

            while (i < len)
            {
                c1         = ba[i++];
                isInString = (inString > 0);

                /* MATCH COMMENTS / STRING LITTERALS */

                switch (matching)
                {
                // look for comment block/line and preprocessor commands
                case 0:
                    if (!isInString)
                    {
                        // new comment
                        if (c1 == '/')
                        {
                            c2 = ba[i];
                            if (c2 == '/')
                            {
                                matching = 1;
                                inCode   = false;
                                i++;
                                continue;
                            }
                            else if (c2 == '*')
                            {
                                matching = 2;
                                inCode   = false;
                                i++;
                                while (i < len - 1)
                                {
                                    c2 = ba[i];
                                    if (c2 == '*' && ba[i + 1] != '/')
                                    {
                                        i++;
                                    }
                                    else
                                    {
                                        break;
                                    }
                                }
                                continue;
                            }
                        }
                        // don't look for comments in strings
                        else if (c1 == '"')
                        {
                            isInString = true;
                            inString   = 1;
                        }
                        else if (c1 == '\'')
                        {
                            isInString = true;
                            inString   = 2;
                        }
                        // preprocessor statements
                        else if (c1 == '#')
                        {
                            c2 = ba[i];
                            if (i < 2 || ba[i - 2] < 33 && c2 >= 'a' && c2 <= 'z')
                            {
                                matching = 3;
                                inCode   = false;
                                continue;
                            }
                        }
                    }
                    // end of string
                    else if (isInString)
                    {
                        if (c1 == '\\')
                        {
                            i++;
                        }
                        else if ((inString == 1) && (c1 == '"'))
                        {
                            inString = 0;
                        }
                        else if ((inString == 2) && (c1 == '\''))
                        {
                            inString = 0;
                        }
                    }
                    break;

                // skip commented line
                case 1:
                    if (c1 == 10 || c1 == 13)
                    {
                        // ignore single comments
                        commentLength = 0;
                        inCode        = true;
                        matching      = 0;
                    }
                    break;

                // skip commented block
                case 2:
                    if (c1 == '*')
                    {
                        bool end = false;
                        while (i < len)
                        {
                            c2 = ba[i];
                            if (c2 == '/')
                            {
                                end = true;
                                break;
                            }
                            else if (c2 == '*')
                            {
                                i++;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (end)
                        {
                            lastComment = (commentLength > 0) ? new string(commentBuffer, 0, commentLength) : null;
                            // TODO  parse for TODO statements?
                            commentLength = 0;
                            inCode        = true;
                            matching      = 0;
                            i++;
                            continue;
                        }
                    }
                    break;

                // directive/preprocessor statement
                case 3:
                    if (c1 == 10 || c1 == 13)
                    {
                        if (commentLength > 0)
                        {
                            string directive = new string(commentBuffer, 0, commentLength);
                            // TODO Store haXe directives in model

                            // FD cache custom directive
                            if (parentPath != null && directive.StartsWith("file-cache "))
                            {
                                model.Version = version;
                                model         = new FileModel(directive.Substring(11), cacheLastWriteTime);
                                parentPath.AddFile(model);
                                goto resetParser;
                            }
                        }
                        commentLength = 0;
                        inCode        = true;
                        matching      = 0;
                    }
                    break;
                }

                /* LINE/COLUMN NUMBER */

                if (c1 == 10 || c1 == 13)
                {
                    line++;
                    if (c1 == 13 && ba[i] == 10)
                    {
                        i++;
                    }
                }


                /* SKIP CONTENT */

                if (!inCode)
                {
                    // store comments
                    if (matching == 2 || (matching == 3 && (haXe || parentPath != null)))
                    {
                        if (commentLength < COMMENTS_BUFFER)
                        {
                            commentBuffer[commentLength++] = c1;
                        }
                    }
                    continue;
                }
                else if (isInString)
                {
                    // store parameter default value
                    if (inParams && inValue && valueLength < VALUE_BUFFER)
                    {
                        valueBuffer[valueLength++] = c1;
                    }
                    continue;
                }
                if (braceCount > 0)
                {
                    if (c1 == '}')
                    {
                        braceCount--;
                        if (braceCount == 0 && curMethod != null)
                        {
                            //Debug.WriteLine("} "+curMethod.Name+" @"+line);
                            curMethod.LineTo = line;
                            curMethod        = null;
                        }
                    }
                    else if (c1 == '{')
                    {
                        braceCount++;
                    }
                    continue;
                }


                /* PARSE DECLARATION VALUES/TYPES */

                if (inValue)
                {
                    if (c1 == '{')
                    {
                        paramBraceCount++;
                    }
                    else if (c1 == '}' && paramBraceCount > 0)
                    {
                        paramBraceCount--;
                        if (paramBraceCount == 0 && paramParCount == 0 && paramSqCount == 0 && valueLength < VALUE_BUFFER)
                        {
                            valueBuffer[valueLength++] = '}';
                        }
                    }
                    else if (c1 == '(')
                    {
                        paramParCount++;
                    }
                    else if (c1 == ')' && paramParCount > 0)
                    {
                        paramParCount--;
                    }
                    else if (c1 == '(')
                    {
                        paramSqCount++;
                    }
                    else if (c1 == ')' && paramSqCount > 0)
                    {
                        paramSqCount--;
                    }
                    else if (paramTempCount > 0)
                    {
                        if (c1 == '<')
                        {
                            paramTempCount++;
                        }
                        else if (c1 == '>')
                        {
                            paramTempCount--;
                        }
                    }

                    // end of value
                    if (paramBraceCount == 0 && paramParCount == 0 && paramSqCount == 0 && paramTempCount == 0 &&
                        (c1 == ',' || c1 == ';' || c1 == '}' || (inParams && c1 == ')') || inType))
                    {
                        inValue = false;
                        length  = 0;
                        if (inType)
                        {
                            valueBuffer[valueLength++] = c1;
                        }
                    }

                    // in params, store the default value
                    else if ((inParams || inType) && valueLength < VALUE_BUFFER)
                    {
                        if (c1 < 32)
                        {
                            if (valueLength > 0 && valueBuffer[valueLength - 1] != ' ')
                            {
                                valueBuffer[valueLength++] = ' ';
                            }
                        }
                        else
                        {
                            valueBuffer[valueLength++] = c1;
                        }
                    }

                    // only try to detect keywords
                    if (c1 < 'a' || c1 > 'z')
                    {
                        hadWS = true;
                        continue;
                    }
                }
                // store parameter value
                if (!inValue && valueLength > 0)
                {
                    string param = new string(valueBuffer, 0, valueLength);

                    if (valueKeyword != null)
                    {
                        int p = param.LastIndexOf(valueKeyword.Text);
                        if (p > 0)
                        {
                            param = param.Substring(0, p).TrimEnd();
                        }
                    }
                    //
                    if (curMember == null)
                    {
                        if (inType)
                        {
                            prevToken.Text     = curToken.Text;
                            prevToken.Line     = curToken.Line;
                            prevToken.Position = curToken.Position;
                            curToken.Text      = param;
                            curToken.Line      = tokLine;
                            curToken.Position  = tokPos;
                            EvalToken(true, false, i - 1 - valueLength);
                            evalKeyword = true;
                            evalToken   = 0;
                        }
                    }
                    else if (inType)
                    {
                        //Debug.WriteLine("      : "+param);
                        //
                        foundColon     = false;
                        curMember.Type = param;
                    }
                    else
                    {
                        //Debug.WriteLine("      = "+param);
                        //
                        curMember.Parameters = new ArrayList();
                        curMember.Parameters.Add(param);
                    }
                    //
                    valueLength = 0;
                    length      = 0;
                }

                /* TOKENIZATION */

                // whitespace
                if (c1 <= 32)
                {
                    hadWS = true;
                    continue;
                }
                // a dot can be in an identifier
                if (c1 == '.')
                {
                    if (length > 0 || (inParams && version == 3))
                    {
                        hadWS   = false;
                        hadDot  = true;
                        addChar = true;
                    }
                    else
                    {
                        continue;
                    }
                }
                else
                {
                    // should we evaluate the token?
                    if (hadWS && !hadDot && length > 0)
                    {
                        evalToken = (evalKeyword) ? 1 : 2;
                    }
                    hadWS  = false;
                    hadDot = false;

                    // valid char for keyword
                    if (c1 >= 'a' && c1 <= 'z')
                    {
                        addChar = true;
                    }
                    else
                    {
                        // valid chars for identifiers
                        if (c1 >= 'A' && c1 <= 'Z')
                        {
                            addChar = true;
                        }
                        else if (c1 == '$' || c1 == '_')
                        {
                            addChar = true;
                        }
                        else if (length > 0)
                        {
                            if (c1 >= '0' && c1 <= '9')
                            {
                                addChar = true;
                            }
                            else if (c1 == '*' && context == FlagType.Import)
                            {
                                addChar = true;
                            }
                            // haXe template types
                            else if (haXe && c1 == '<')
                            {
                                inValue     = true;
                                inType      = true;
                                valueLength = 0;
                                for (int j = 0; j < length; j++)
                                {
                                    valueBuffer[valueLength++] = buffer[j];
                                }
                                valueBuffer[valueLength++] = c1;
                                length          = 0;
                                paramBraceCount = 0;
                                paramParCount   = 0;
                                paramSqCount    = 0;
                                paramTempCount  = 1;
                                continue;
                            }
                            else
                            {
                                evalToken = (evalKeyword) ? 1 : 2;
                            }
                        }
                        // star is valid in import statements
                        else if (c1 == '*' && version == 3 && !foundColon)
                        {
                            addChar = true;
                        }

                        // these chars are not valid in keywords
                        if (length > 0)
                        {
                            evalKeyword = false;
                        }
                    }

                    // eval this word
                    if (evalToken > 0)
                    {
                        prevToken.Text     = curToken.Text;
                        prevToken.Line     = curToken.Line;
                        prevToken.Position = curToken.Position;
                        curToken.Text      = new string(buffer, 0, length);
                        curToken.Line      = tokLine;
                        curToken.Position  = tokPos;
                        EvalToken(!inValue, (evalToken == 1), i - 1 - length);
                        length      = 0;
                        evalKeyword = true;
                        evalToken   = 0;
                    }

                    // start of block
                    if (c1 == '{')
                    {
                        if (context == FlagType.Package || context == FlagType.Class)
                        {
                        }
                        else if (context == FlagType.Enum)
                        {
                            inEnum = true;
                        }
                        else if (foundColon && haXe && length == 0)
                        {
                            inValue     = true;
                            inType      = true;
                            valueLength = 0;
                            valueBuffer[valueLength++] = c1;
                            paramBraceCount            = 1;
                            paramParCount  = 0;
                            paramSqCount   = 0;
                            paramTempCount = 0;
                            continue;
                        }
                        else
                        {
                            braceCount++;
                            //Debug.WriteLine("{"+braceCount);
                        }
                    }

                    // end of block
                    else if (c1 == '}')
                    {
                        // outside of a method, the '}' ends the current class
                        if (curClass != null)
                        {
                            //Debug.WriteLine("} class "+curClass+" @"+line);
                            if (curClass != null)
                            {
                                curClass.LineTo = line;
                            }
                            curClass   = null;
                            tryPackage = true;
                        }
                    }

                    // member type declaration
                    else if (c1 == ':')
                    {
                        foundColon = true;
                    }

                    // next variable declaration
                    else if (c1 == ',')
                    {
                        if (context == FlagType.Variable)
                        {
                            foundKeyword = FlagType.Variable;
                        }
                    }

                    else if (c1 == '(')
                    {
                        // beginning of method parameters
                        if (context == FlagType.Function)
                        {
                            context  = FlagType.Variable;
                            inParams = true;
                            if (curMember == null)
                            {
                                context = FlagType.Function;
                                if ((curModifiers & FlagType.Getter) > 0)
                                {
                                    curModifiers -= FlagType.Getter;
                                    EvalToken(true, false, i);
                                    curMethod = curMember;
                                }
                                else if ((curModifiers & FlagType.Setter) > 0)
                                {
                                    curModifiers -= FlagType.Setter;
                                    EvalToken(true, false, i);
                                    curMethod = curMember;
                                }
                                else
                                {
                                    inParams = false;
                                    context  = 0;
                                }
                            }
                            else
                            {
                                curMethod = curMember;
                                Debug.WriteLine("{ " + curMember.Name);
                            }
                        }

                        // an Enum value with parameters
                        else if (inEnum && curToken != null)
                        {
                            //Debug.WriteLine("********** enum construc "+curToken);
                            context         = FlagType.Variable;
                            inParams        = true;
                            curMethod       = new MemberModel();
                            curMethod.Name  = curToken.Text;
                            curMethod.Flags = curModifiers | FlagType.Function | FlagType.Enum;
                            //
                            if (curClass != null)
                            {
                                curClass.Members.Add(curMethod);
                            }
                        }
                    }

                    // end of statement
                    else if (c1 == ';')
                    {
                        context   = 0;
                        modifiers = 0;
                        inParams  = false;
                        curMember = null;
                        //curMethod = null;
                    }

                    // end of method parameters
                    else if (c1 == ')' && inParams)
                    {
                        context   = (inEnum) ? FlagType.Enum : 0;
                        modifiers = 0;
                        inParams  = false;
                        curMember = curMethod;
                    }

                    // skip value of a declared variable
                    else if (c1 == '=' && context == FlagType.Variable)
                    {
                        if (!inValue)
                        {
                            inValue         = true;
                            inType          = false;
                            paramBraceCount = 0;
                            paramParCount   = 0;
                            paramSqCount    = 0;
                            paramTempCount  = 0;
                            valueLength     = 0;
                        }
                    }

                    // special haXe types: T -> T
                    else if (haXe && c1 == '-' && curMember != null)
                    {
                        if (ba[i] == '>')
                        {
                            curMember.Type += " ->";
                        }
                    }
                }

                // put in buffer
                if (addChar)
                {
                    if (length < TOKEN_BUFFER)
                    {
                        buffer[length++] = c1;
                    }

                    if (length == 1)
                    {
                        tokPos  = i - 1;
                        tokLine = line;
                    }
                    addChar = false;
                }
            }

            // parsing done!
            model.Version = version;
        }