INILexer.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
  3. * Copyright (c) 2023, Sam Atkins <atkinssj@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "INILexer.h"
  8. #include <AK/CharacterTypes.h>
  9. #include <AK/Vector.h>
  10. namespace GUI {
  11. IniLexer::IniLexer(StringView input)
  12. : m_input(input)
  13. , m_iterator(m_input.begin())
  14. {
  15. }
  16. u32 IniLexer::peek(size_t offset) const
  17. {
  18. return m_iterator.peek(offset).value_or(0);
  19. }
  20. u32 IniLexer::consume()
  21. {
  22. VERIFY(m_iterator != m_input.end());
  23. u32 ch = *m_iterator;
  24. ++m_iterator;
  25. if (ch == '\n') {
  26. m_position.line++;
  27. m_position.column = 0;
  28. } else {
  29. m_position.column++;
  30. }
  31. return ch;
  32. }
  33. Vector<IniToken> IniLexer::lex()
  34. {
  35. Vector<IniToken> tokens;
  36. IniPosition token_start_position;
  37. auto emit_token = [&](auto type) {
  38. IniToken token;
  39. token.m_type = type;
  40. token.m_start = m_position;
  41. consume();
  42. token.m_end = m_position;
  43. tokens.append(token);
  44. };
  45. auto begin_token = [&] {
  46. token_start_position = m_position;
  47. };
  48. auto commit_token = [&](auto type) {
  49. IniToken token;
  50. token.m_type = type;
  51. token.m_start = token_start_position;
  52. token.m_end = m_position;
  53. tokens.append(token);
  54. };
  55. while (m_iterator != m_input.end()) {
  56. auto ch = peek();
  57. if (is_ascii_space(ch)) {
  58. begin_token();
  59. while (is_ascii_space(peek()))
  60. consume();
  61. commit_token(IniToken::Type::Whitespace);
  62. continue;
  63. }
  64. // ;Comment or #Comment
  65. if (ch == ';' || ch == '#') {
  66. begin_token();
  67. while (peek() && peek() != '\n')
  68. consume();
  69. commit_token(IniToken::Type::Comment);
  70. continue;
  71. }
  72. // [Section]
  73. if (ch == '[') {
  74. // [ Token
  75. begin_token();
  76. consume();
  77. commit_token(IniToken::Type::LeftBracket);
  78. // Section
  79. begin_token();
  80. while (peek() && !(peek() == ']' || peek() == '\n'))
  81. consume();
  82. commit_token(IniToken::Type::Section);
  83. // ] Token
  84. if (peek() && peek() == ']') {
  85. begin_token();
  86. consume();
  87. commit_token(IniToken::Type::RightBracket);
  88. }
  89. continue;
  90. }
  91. // Empty Line
  92. if (ch == '\n') {
  93. consume();
  94. emit_token(IniToken::Type::Unknown);
  95. continue;
  96. }
  97. // Name=Value
  98. begin_token();
  99. while (peek() && !(peek() == '=' || peek() == '\n'))
  100. consume();
  101. commit_token(IniToken::Type::Name);
  102. if (peek() && peek() == '=') {
  103. begin_token();
  104. consume();
  105. commit_token(IniToken::Type::Equal);
  106. }
  107. if (peek()) {
  108. begin_token();
  109. while (peek() && peek() != '\n')
  110. consume();
  111. commit_token(IniToken::Type::Value);
  112. }
  113. }
  114. return tokens;
  115. }
  116. }