INILexer.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  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/Vector.h>
  8. #include <ctype.h>
  9. namespace GUI {
  10. IniLexer::IniLexer(const 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. m_previous_position = m_position;
  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. size_t token_start_index = 0;
  37. IniPosition token_start_position;
  38. auto emit_token = [&](auto type) {
  39. IniToken token;
  40. token.m_type = type;
  41. token.m_start = m_position;
  42. token.m_end = m_position;
  43. tokens.append(token);
  44. consume();
  45. };
  46. auto begin_token = [&] {
  47. token_start_index = m_index;
  48. token_start_position = m_position;
  49. };
  50. auto commit_token = [&](auto type) {
  51. IniToken token;
  52. token.m_type = type;
  53. token.m_start = token_start_position;
  54. token.m_end = m_previous_position;
  55. tokens.append(token);
  56. };
  57. while (m_index < m_input.length()) {
  58. auto ch = peek();
  59. if (isspace(ch)) {
  60. begin_token();
  61. while (isspace(peek()))
  62. consume();
  63. commit_token(IniToken::Type::Whitespace);
  64. continue;
  65. }
  66. // ;Comment
  67. if (ch == ';') {
  68. begin_token();
  69. while (peek() && peek() != '\n')
  70. consume();
  71. commit_token(IniToken::Type::Comment);
  72. continue;
  73. }
  74. // [Section]
  75. if (ch == '[') {
  76. // [ Token
  77. begin_token();
  78. consume();
  79. commit_token(IniToken::Type::LeftBracket);
  80. // Section
  81. begin_token();
  82. while (peek() && !(peek() == ']' || peek() == '\n'))
  83. consume();
  84. commit_token(IniToken::Type::section);
  85. // ] Token
  86. if (peek() && peek() == ']') {
  87. begin_token();
  88. consume();
  89. commit_token(IniToken::Type::RightBracket);
  90. }
  91. continue;
  92. }
  93. // Empty Line
  94. if (ch == '\n') {
  95. consume();
  96. emit_token(IniToken::Type::Unknown);
  97. continue;
  98. }
  99. // Name=Value
  100. begin_token();
  101. while (peek() && !(peek() == '=' || peek() == '\n'))
  102. consume();
  103. commit_token(IniToken::Type::Name);
  104. if (peek() && peek() == '=') {
  105. begin_token();
  106. consume();
  107. commit_token(IniToken::Type::Equal);
  108. }
  109. if (peek()) {
  110. begin_token();
  111. while (peek() && peek() != '\n')
  112. consume();
  113. commit_token(IniToken::Type::Value);
  114. }
  115. }
  116. return tokens;
  117. }
  118. }