summaryrefslogtreecommitdiff
path: root/misc/scanners.adb
blob: 296268bf0cb4432d7572a3686618efdd5aab20e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

package body Scanners is


    function Create
           (Input         : in String;
            Delimiters    : in String  := Default_Delimiters;
            Return_Delims : in Boolean := False)
        return Scanner is
    begin
        return This : Scanner do
            This.Text := UB.To_Unbounded_String (Input);
            This.Delimiters := SM.To_Set (Delimiters);
            This.Return_Delims := Return_Delims;
            This.Reset;
        end return;
    end Create;


    function Has_More_Tokens
           (This : in Scanner)
        return Boolean is
    begin
        return This.Next_Start <= This.Next_Finish;
    end Has_More_Tokens;


    procedure Queue_Next
           (This : in out Scanner) is
    begin
        if This.Return_Delims and then
           SM.Is_In (UB.Element (This.Text, This.Position), Default_Delimiter_Set)
        then
            This.Next_Start := This.Position;
            This.Next_Finish := This.Position;
        else
            UB.Find_Token
               (This.Text, This.Delimiters, This.Position,
                Ada.Strings.Outside, This.Next_Start, This.Next_Finish);
        end if;
        This.Position := This.Next_Finish + 1;
    end Queue_Next;


    function Next_Token
           (This : in out Scanner)
        return String
    is
        Old_Start  : Positive := This.Next_Start;
        Old_Finish : Natural  := This.Next_Finish;
    begin
        if not This.Has_More_Tokens then
            return "";
        end if;
        if This.Position > UB.Length (This.Text) then
            This.Next_Finish := This.Next_Start - 1;
        else
            This.Queue_Next;
        end if;
        return UB.Slice (This.Text, Old_Start, Old_Finish);
    end Next_Token;


    function Remaining_Token_Count
           (This : in Scanner)
        return Natural
    is
        --  Copying an entire Scanner like this is not efficient,
        --  but this function will never be efficient, so at the
        --  moment I am choosing to favour clearer code.
        Test_Scan : Scanner := This;
        Count     : Natural := 0;
    begin
        while Test_Scan.Has_More_Tokens loop
            Count := Count + 1;
            exit when Test_Scan.Position > UB.Length (Test_Scan.Text);
            Test_Scan.Queue_Next;
        end loop;
        return Count;
    end Remaining_Token_Count;


    procedure Reset
           (This : in out Scanner) is
    begin
        This.Position := 1;
        if UB.Length (This.Text) > 0 then
            This.Queue_Next;
        else
            This.Next_Start := 1;
            This.Next_Finish := 0;
        end if;
    end Reset;


end Scanners;