GMLParser.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/GenericLexer.h>
  7. #include <AK/JsonObject.h>
  8. #include <AK/JsonValue.h>
  9. #include <AK/Queue.h>
  10. #include <LibGUI/GMLLexer.h>
  11. #include <LibGUI/GMLParser.h>
  12. #include <ctype.h>
  13. namespace GUI {
  14. static Optional<JsonValue> parse_core_object(Queue<GMLToken>& tokens)
  15. {
  16. JsonObject object;
  17. JsonArray children;
  18. auto peek = [&] {
  19. if (tokens.is_empty())
  20. return GMLToken::Type::Unknown;
  21. return tokens.head().m_type;
  22. };
  23. while (peek() == GMLToken::Type::Comment)
  24. tokens.dequeue();
  25. if (peek() != GMLToken::Type::ClassMarker) {
  26. dbgln("Expected class marker");
  27. return {};
  28. }
  29. tokens.dequeue();
  30. if (peek() != GMLToken::Type::ClassName) {
  31. dbgln("Expected class name");
  32. return {};
  33. }
  34. auto class_name = tokens.dequeue();
  35. object.set("class", JsonValue(class_name.m_view));
  36. if (peek() != GMLToken::Type::LeftCurly) {
  37. // Empty object
  38. return object;
  39. }
  40. tokens.dequeue();
  41. for (;;) {
  42. if (peek() == GMLToken::Type::RightCurly) {
  43. // End of object
  44. break;
  45. }
  46. if (peek() == GMLToken::Type::ClassMarker) {
  47. // It's a child object.
  48. auto value = parse_core_object(tokens);
  49. if (!value.has_value()) {
  50. dbgln("Parsing child object failed");
  51. return {};
  52. }
  53. if (!value.value().is_object()) {
  54. dbgln("Expected child to be Core::Object");
  55. return {};
  56. }
  57. children.append(value.release_value());
  58. } else if (peek() == GMLToken::Type::Identifier) {
  59. // It's a property.
  60. auto property_name = tokens.dequeue();
  61. if (property_name.m_view.is_empty()) {
  62. dbgln("Expected non-empty property name");
  63. return {};
  64. }
  65. if (peek() != GMLToken::Type::Colon) {
  66. dbgln("Expected ':'");
  67. return {};
  68. }
  69. tokens.dequeue();
  70. JsonValue value;
  71. if (peek() == GMLToken::Type::ClassMarker) {
  72. auto parsed_value = parse_core_object(tokens);
  73. if (!parsed_value.has_value())
  74. return {};
  75. if (!parsed_value.value().is_object()) {
  76. dbgln("Expected property to be Core::Object");
  77. return {};
  78. }
  79. value = parsed_value.release_value();
  80. } else if (peek() == GMLToken::Type::JsonValue) {
  81. auto value_string = tokens.dequeue();
  82. auto parsed_value = JsonValue::from_string(value_string.m_view);
  83. if (!parsed_value.has_value()) {
  84. dbgln("Expected property to be JSON value");
  85. return {};
  86. }
  87. value = parsed_value.release_value();
  88. }
  89. object.set(property_name.m_view, move(value));
  90. } else if (peek() == GMLToken::Type::Comment) {
  91. tokens.dequeue();
  92. } else {
  93. dbgln("Expected child, property, comment, or }}");
  94. return {};
  95. }
  96. }
  97. if (peek() != GMLToken::Type::RightCurly) {
  98. dbgln("Expected }}");
  99. return {};
  100. }
  101. tokens.dequeue();
  102. if (!children.is_empty())
  103. object.set("children", move(children));
  104. return object;
  105. }
  106. JsonValue parse_gml(const StringView& string)
  107. {
  108. auto lexer = GMLLexer(string);
  109. Queue<GMLToken> tokens;
  110. for (auto& token : lexer.lex())
  111. tokens.enqueue(token);
  112. auto root = parse_core_object(tokens);
  113. if (!root.has_value())
  114. return JsonValue();
  115. return root.release_value();
  116. }
  117. }