using System.Collections.Generic; 
 | 
using System.Text.RegularExpressions; 
 | 
using System.IO; 
 | 
using System.Linq; 
 | 
using System; 
 | 
  
 | 
#if UNITY_XCODE_API_BUILD 
 | 
namespace UnityEditor.iOS.Xcode.PBX 
 | 
#else 
 | 
namespace UnityEditor.iOS.Xcode.Custom.PBX 
 | 
#endif 
 | 
{ 
 | 
    enum TokenType 
 | 
    { 
 | 
        EOF, 
 | 
        Invalid, 
 | 
        String, 
 | 
        QuotedString, 
 | 
        Comment, 
 | 
         
 | 
        Semicolon,  // ; 
 | 
        Comma,      // , 
 | 
        Eq,         // = 
 | 
        LParen,     // ( 
 | 
        RParen,     // ) 
 | 
        LBrace,     // { 
 | 
        RBrace,     // }       
 | 
    } 
 | 
     
 | 
    class Token 
 | 
    { 
 | 
        public TokenType type; 
 | 
         
 | 
        // the line of the input stream the token starts in (0-based) 
 | 
        public int line; 
 | 
         
 | 
        // start and past-the-end positions of the token in the input stream 
 | 
        public int begin, end; 
 | 
    } 
 | 
     
 | 
    class TokenList : List<Token> 
 | 
    { 
 | 
    } 
 | 
     
 | 
    class Lexer 
 | 
    { 
 | 
        string text; 
 | 
        int pos; 
 | 
        int length; 
 | 
        int line; 
 | 
  
 | 
        public static TokenList Tokenize(string text) 
 | 
        { 
 | 
            var lexer = new Lexer(); 
 | 
            lexer.SetText(text); 
 | 
            return lexer.ScanAll(); 
 | 
        } 
 | 
         
 | 
        public void SetText(string text) 
 | 
        { 
 | 
            this.text = text + "    "; // to prevent out-of-bounds access during look ahead 
 | 
            pos = 0; 
 | 
            length = text.Length; 
 | 
            line = 0; 
 | 
        } 
 | 
         
 | 
        public TokenList ScanAll() 
 | 
        { 
 | 
            var tokens = new TokenList(); 
 | 
             
 | 
            while (true) 
 | 
            { 
 | 
                var tok = new Token(); 
 | 
                ScanOne(tok); 
 | 
                tokens.Add(tok); 
 | 
                if (tok.type == TokenType.EOF) 
 | 
                    break; 
 | 
            } 
 | 
            return tokens; 
 | 
        } 
 | 
         
 | 
        void UpdateNewlineStats(char ch) 
 | 
        { 
 | 
            if (ch == '\n') 
 | 
                line++; 
 | 
        } 
 | 
         
 | 
        // tokens list is modified in the case when we add BrokenLine token and need to remove already 
 | 
        // added tokens for the current line 
 | 
        void ScanOne(Token tok) 
 | 
        { 
 | 
            while (true) 
 | 
            { 
 | 
                while (pos < length && Char.IsWhiteSpace(text[pos])) 
 | 
                { 
 | 
                    UpdateNewlineStats(text[pos]); 
 | 
                    pos++; 
 | 
                } 
 | 
                 
 | 
                if (pos >= length) 
 | 
                { 
 | 
                    tok.type = TokenType.EOF; 
 | 
                    break; 
 | 
                } 
 | 
                 
 | 
                char ch = text[pos]; 
 | 
                char ch2 = text[pos+1]; 
 | 
                 
 | 
                if (ch == '\"') 
 | 
                    ScanQuotedString(tok); 
 | 
                else if (ch == '/' && ch2 == '*') 
 | 
                    ScanMultilineComment(tok); 
 | 
                else if (ch == '/' && ch2 == '/') 
 | 
                    ScanComment(tok); 
 | 
                else if (IsOperator(ch)) 
 | 
                    ScanOperator(tok); 
 | 
                else 
 | 
                    ScanString(tok); // be more robust and accept whatever is left 
 | 
                return; 
 | 
            }     
 | 
        } 
 | 
         
 | 
        void ScanString(Token tok) 
 | 
        { 
 | 
            tok.type = TokenType.String; 
 | 
            tok.begin = pos; 
 | 
            while (pos < length) 
 | 
            { 
 | 
                char ch = text[pos]; 
 | 
                char ch2 = text[pos+1]; 
 | 
                 
 | 
                if (Char.IsWhiteSpace(ch)) 
 | 
                    break; 
 | 
                else if (ch == '\"') 
 | 
                    break; 
 | 
                else if (ch == '/' && ch2 == '*') 
 | 
                    break; 
 | 
                else if (ch == '/' && ch2 == '/') 
 | 
                    break; 
 | 
                else if (IsOperator(ch)) 
 | 
                    break; 
 | 
                pos++; 
 | 
            } 
 | 
            tok.end = pos; 
 | 
            tok.line = line; 
 | 
        } 
 | 
         
 | 
        void ScanQuotedString(Token tok) 
 | 
        { 
 | 
            tok.type = TokenType.QuotedString; 
 | 
            tok.begin = pos; 
 | 
            pos++; 
 | 
             
 | 
            while (pos < length) 
 | 
            { 
 | 
                // ignore escaped quotes 
 | 
                if (text[pos] == '\\' && text[pos+1] == '\"') 
 | 
                { 
 | 
                    pos += 2; 
 | 
                    continue; 
 | 
                } 
 | 
             
 | 
                // note that we close unclosed quotes 
 | 
                if (text[pos] == '\"') 
 | 
                    break; 
 | 
                 
 | 
                UpdateNewlineStats(text[pos]); 
 | 
                pos++; 
 | 
            } 
 | 
            pos++; 
 | 
            tok.end = pos; 
 | 
            tok.line = line; 
 | 
        } 
 | 
  
 | 
        void ScanMultilineComment(Token tok) 
 | 
        { 
 | 
            tok.type = TokenType.Comment; 
 | 
            tok.begin = pos; 
 | 
            pos += 2; 
 | 
             
 | 
            while (pos < length) 
 | 
            { 
 | 
                if (text[pos] == '*' && text[pos+1] == '/') 
 | 
                    break; 
 | 
                 
 | 
                // we support multiline comments 
 | 
                UpdateNewlineStats(text[pos]); 
 | 
                pos++; 
 | 
            } 
 | 
            pos += 2; 
 | 
            tok.end = pos; 
 | 
            tok.line = line; 
 | 
        } 
 | 
  
 | 
        void ScanComment(Token tok) 
 | 
        { 
 | 
            tok.type = TokenType.Comment; 
 | 
            tok.begin = pos; 
 | 
            pos += 2; 
 | 
  
 | 
            while (pos < length) 
 | 
            { 
 | 
                if (text[pos] == '\n') 
 | 
                    break; 
 | 
                pos++; 
 | 
            } 
 | 
            UpdateNewlineStats(text[pos]); 
 | 
            pos++; 
 | 
            tok.end = pos; 
 | 
            tok.line = line; 
 | 
        } 
 | 
         
 | 
        bool IsOperator(char ch) 
 | 
        { 
 | 
            if (ch == ';' || ch == ',' || ch == '=' || ch == '(' || ch == ')' || ch == '{' || ch == '}') 
 | 
                return true; 
 | 
            return false; 
 | 
        } 
 | 
  
 | 
        void ScanOperator(Token tok) 
 | 
        { 
 | 
            switch (text[pos]) 
 | 
            { 
 | 
                case ';': ScanOperatorSpecific(tok, TokenType.Semicolon); return; 
 | 
                case ',': ScanOperatorSpecific(tok, TokenType.Comma); return; 
 | 
                case '=': ScanOperatorSpecific(tok, TokenType.Eq); return; 
 | 
                case '(': ScanOperatorSpecific(tok, TokenType.LParen); return; 
 | 
                case ')': ScanOperatorSpecific(tok, TokenType.RParen); return; 
 | 
                case '{': ScanOperatorSpecific(tok, TokenType.LBrace); return; 
 | 
                case '}': ScanOperatorSpecific(tok, TokenType.RBrace); return; 
 | 
                default: return; 
 | 
            } 
 | 
        } 
 | 
         
 | 
        void ScanOperatorSpecific(Token tok, TokenType type) 
 | 
        { 
 | 
            tok.type = type; 
 | 
            tok.begin = pos; 
 | 
            pos++; 
 | 
            tok.end = pos; 
 | 
            tok.line = line; 
 | 
        } 
 | 
    } 
 | 
     
 | 
  
 | 
} // namespace UnityEditor.iOS.Xcode 
 |