GMLParser.cpp 3.8 KB

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