Пример #1
0
        public ICollection <IMapRangeItem> GetMap(string Text, string Ext, MapperOptions Options)
        {
            PascalFileType pType = PascalFileType.pas;

            if (".dpr".Equals(Ext, StringComparison.InvariantCultureIgnoreCase))
            {
                pType = PascalFileType.dpr;
            }
            else if (".dfm".Equals(Ext, StringComparison.InvariantCultureIgnoreCase))
            {
                pType = PascalFileType.dfm;
            }
            return(Parse(Text, pType, Options));
        }
Пример #2
0
        public ICollection <IMapRangeItem> Parse(string Text, PascalFileType pType, MapperOptions Options)
        {
            var          mapMethods = Options.HasFlag(MapperOptions.MapMethods);
            var          res = new List <IMapRangeItem>();
            int          Start = -1, End = -1, newWordStart = -1;
            bool         uses      = false;
            bool         unit      = false;
            var          value     = string.Empty;
            var          comb      = 0;
            var          word      = string.Empty;
            var          wordStart = -1;
            var          links     = new List <IMapUnitLink>();
            Action <int> setWord2  = (idx) =>
            {
                if (newWordStart > -1)
                {
                    wordStart    = newWordStart;
                    word         = Text.Substring(newWordStart, idx - newWordStart);
                    newWordStart = -1;
                    if (word.Equals("uses", StringComparison.InvariantCultureIgnoreCase))
                    {
                        word      = string.Empty;
                        wordStart = -1;
                        uses      = true;
                    }
                }
            };
            Action <int> setWord = pType == PascalFileType.dfm ? (_ => { }) : (Action <int>)((idx) =>
            {
                if (newWordStart > -1)
                {
                    setWord2(idx);
                    if (uses)
                    {
                        setWord = setWord2;
                    }
                    if (unit)
                    {
                        res.Add(new PascalUnitEntry(word, idx - word.Length, idx, links));
                        setWord   = setWord2;
                        wordStart = -1;
                        unit      = false;
                    }
                    else if (word.Equals("unit", StringComparison.InvariantCultureIgnoreCase))
                    {
                        unit = true;
                    }
                }
            });
            Stack <KeyValuePair <string, int> > methods = new Stack <KeyValuePair <string, int> >();

            for (int idx = 0; idx < Text.Length; idx++)
            {
                switch (Text[idx])
                {
                case '\0':
                    if (pType == PascalFileType.dfm)
                    {
                        throw new MapperFixableException("Символ конца строки внутри строки. Возможно бинарный формат *.dfm.");
                    }
                    else
                    {
                        throw new MapperException("Символ конца строки внутри строки.");
                    }

                case '/':
                    if (idx > 0 && Text[idx - 1] == '/')
                    {
                        var start = idx - 1;
                        while (++idx < Text.Length && !(Text[idx] == '\r' || Text[idx] == '\n'))
                        {
                            ;
                        }
                        res.Add(new MapForeColorRangeItemBase(start, idx + 1, CommentBrush));
                    }
                    break;

                case '{':
                {
                    var start = idx;
                    while (++idx < Text.Length && Text[idx] != '}')
                    {
                        ;
                    }
                    res.Add(new MapForeColorRangeItemBase(start, idx + 1, (idx > start && Text[start + 1] == '$') ? DirectiveBrush : CommentBrush));
                }
                break;

                case '*':
                    if (idx > 0 && Text[idx - 1] == '(')
                    {
                        var start = idx - 1;
                        while (++idx < Text.Length && !(Text[idx] == ')' && Text[idx - 1] == '*'))
                        {
                            ;
                        }
                        res.Add(new MapForeColorRangeItemBase(start, idx + 1, CommentBrush));
                    }
                    break;

                case '#':
                {
                    if (Start == -1)
                    {
                        Start = idx;
                    }
                    int start = idx;
                    while (++idx < Text.Length && (char.IsNumber(Text[idx]) || char.IsLetter(Text[idx]) || Text[idx] == '#' || Text[idx] == '$'))
                    {
                        ;
                    }
                    string          str = Text.Substring(start, idx - start);
                    MatchCollection ms  = regex.Matches(str);
                    foreach (Match m in ms)
                    {
                        var code    = m.Groups[1].Value;
                        int intChar = 0;
                        if (string.IsNullOrEmpty(code))
                        {
                            continue;
                        }
                        if (code[0] == '$')
                        {
                            intChar = int.Parse(code.Substring(1), System.Globalization.NumberStyles.HexNumber);
                        }
                        else
                        {
                            intChar = Convert.ToInt32(code);
                        }
                        value += Convert.ToChar(intChar);
                    }
                    End = idx--;
                }
                break;

                case '\'':
                {
                    if (Start == -1)
                    {
                        Start = idx;
                    }
                    int start = idx;
                    int cnt;
                    do
                    {
                        while (++idx < Text.Length && Text[idx] != '\'')
                        {
                            ;
                        }
                        cnt = 0;
                        while (idx < Text.Length && Text[idx] == '\'')
                        {
                            cnt++;
                            idx++;
                        }
                    }while (cnt != 0 && cnt % 2 == 0);
                    value += Text.Substring(start + 1, idx - start - 2);
                    End    = idx--;
                }
                break;

                default:
                {
                    if (Start != -1)
                    {
                        if (comb == 1 && res.Count > 0)
                        {
                            //если был найден только + между строками и предыдущее значение позволяет выполнить сложение строк
                            var prev = res[res.Count - 1] as IMapValueItem;
                            if (prev != null)
                            {
                                res.RemoveAt(res.Count - 1);
                                value = prev.Value + value;
                                Start = prev.Start;
                            }
                        }

                        if (pType == PascalFileType.dfm)
                        {
                            res.Add(new DfmMapItem(value, Start, End));
                        }
                        else if (uses)
                        {
                            //если строка попала в область Uses то запишем её как пустой тип значения, тогда разметка в файле будет но не строковая
                            res.Add(new MapForeColorRangeItemBase(Start, End, Brushes.Red));
                        }
                        else if (regexGUID.IsMatch(value))
                        {
                            res.Add(new MapForeColorRangeItemBase(Start, End, InterfaceBrush));
                        }
                        else
                        {
                            res.Add(new PascalMapItem(value, Start, End));
                        }
                        Start = -1;
                        comb  = 0;
                        value = string.Empty;
                    }
                    //else
                    {
                        //лабуда для записей вида s := 'Error raised at :' + date + #13#10 + 'In file:'#13#10 + filepath
                        //позволяет объединить следующую строку с предыдущей если между ними был только +
                        // в итоге получим 'Error raised at :' и #13#10'In file:'#13#10
                        // вместо 'Error raised at :', #13#10, 'In file:'#13#10
                        switch (Text[idx])
                        {
                        case '+':
                            comb++;
                            newWordStart = -1;
                            continue;

                        case '(':
                            //после метода никаких объединений строк быть не может
                            comb = 2;
                            if (mapMethods && pType != PascalFileType.dfm)
                            {
                                uses = false;
                                setWord(idx);
                                methods.Push(new KeyValuePair <string, int>(word, wordStart));
                                wordStart = -1;
                            }
                            continue;

                        case ')':
                            //после метода никаких объединений строк быть не может
                            comb         = 2;
                            newWordStart = -1;
                            if (mapMethods && pType != PascalFileType.dfm && methods.Count > 0)
                            {
                                var method = methods.Pop();
                                if (method.Value > -1 &&
                                    !method.Key.Equals("class", StringComparison.InvariantCultureIgnoreCase) &&
                                    !method.Key.Equals("if", StringComparison.InvariantCultureIgnoreCase) &&
                                    !method.Key.Equals("or", StringComparison.InvariantCultureIgnoreCase) &&
                                    !method.Key.Equals("and", StringComparison.InvariantCultureIgnoreCase) &&
                                    !method.Key.Equals("xor", StringComparison.InvariantCultureIgnoreCase) &&
                                    !method.Key.Equals("not", StringComparison.InvariantCultureIgnoreCase)
                                    )
                                {
                                    res.Add(new MapMethodItemBase(method.Key, method.Value, idx + 1));
                                }
                            }
                            break;

                        case ' ':
                        case '\t':
                        case '\r':
                        case '\n':
                        case ';':
                        case ',':
                            setWord(idx);
                            if (uses)
                            {
                                uses = Text[idx] != ';';
                                if (wordStart > -1)
                                {
                                    if (!word.Equals("in", StringComparison.InvariantCultureIgnoreCase))
                                    {
                                        var lnk = new MapUnitLinkBase(word, wordStart, wordStart + word.Length);
                                        res.Add(lnk);
                                        links.Add(lnk);
                                    }
                                    wordStart = -1;
                                }
                            }
                            continue;

                        default:
                            //любой отличный от вайтспэйса символ отменяет объединение строк
                            comb = 2;
                            if (char.IsLetterOrDigit(Text[idx]) || Text[idx] == '_' || ((uses || unit) && Text[idx] == '.'))
                            {
                                if (newWordStart == -1)
                                {
                                    newWordStart = idx;
                                }
                            }
                            else
                            {
                                wordStart    = -1;
                                newWordStart = -1;
                            }
                            break;
                        }
                    }
                }
                break;
                }
            }
            return(res);
        }