summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGUI/INILexer.cpp
blob: 6fdf3576b611763077957cf70026cef95a776daa (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "INILexer.h"
#include <AK/CharacterTypes.h>
#include <AK/Vector.h>

namespace GUI {

IniLexer::IniLexer(StringView input)
    : m_input(input)
{
}

char IniLexer::peek(size_t offset) const
{
    if ((m_index + offset) >= m_input.length())
        return 0;
    return m_input[m_index + offset];
}

char IniLexer::consume()
{
    VERIFY(m_index < m_input.length());
    char ch = m_input[m_index++];
    if (ch == '\n') {
        m_position.line++;
        m_position.column = 0;
    } else {
        m_position.column++;
    }
    return ch;
}

Vector<IniToken> IniLexer::lex()
{
    Vector<IniToken> tokens;

    size_t token_start_index = 0;
    IniPosition token_start_position;

    auto emit_token = [&](auto type) {
        IniToken token;
        token.m_type = type;
        token.m_start = m_position;
        consume();
        token.m_end = m_position;
        tokens.append(token);
    };

    auto begin_token = [&] {
        token_start_index = m_index;
        token_start_position = m_position;
    };

    auto commit_token = [&](auto type) {
        IniToken token;
        token.m_type = type;
        token.m_start = token_start_position;
        token.m_end = m_position;
        tokens.append(token);
    };

    while (m_index < m_input.length()) {
        auto ch = peek();

        if (is_ascii_space(ch)) {
            begin_token();
            while (is_ascii_space(peek()))
                consume();
            commit_token(IniToken::Type::Whitespace);
            continue;
        }

        // ;Comment or #Comment
        if (ch == ';' || ch == '#') {
            begin_token();
            while (peek() && peek() != '\n')
                consume();
            commit_token(IniToken::Type::Comment);
            continue;
        }

        // [Section]
        if (ch == '[') {
            // [ Token
            begin_token();
            consume();
            commit_token(IniToken::Type::LeftBracket);

            // Section
            begin_token();
            while (peek() && !(peek() == ']' || peek() == '\n'))
                consume();
            commit_token(IniToken::Type::Section);

            // ] Token
            if (peek() && peek() == ']') {
                begin_token();
                consume();
                commit_token(IniToken::Type::RightBracket);
            }

            continue;
        }

        // Empty Line
        if (ch == '\n') {
            consume();
            emit_token(IniToken::Type::Unknown);
            continue;
        }

        //  Name=Value
        begin_token();
        while (peek() && !(peek() == '=' || peek() == '\n'))
            consume();
        commit_token(IniToken::Type::Name);

        if (peek() && peek() == '=') {
            begin_token();
            consume();
            commit_token(IniToken::Type::Equal);
        }

        if (peek()) {
            begin_token();
            while (peek() && peek() != '\n')
                consume();
            commit_token(IniToken::Type::Value);
        }
    }
    return tokens;
}

}