INILexer.cpp 3.1 KB

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