Parser.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
  4. * Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include "Parser.h"
  9. #include "AST.h"
  10. #include "Lexer.h"
  11. #include <AK/Error.h>
  12. #include <AK/GenericLexer.h>
  13. #include <AK/JsonObject.h>
  14. #include <AK/JsonValue.h>
  15. #include <AK/Queue.h>
  16. #include <AK/RefPtr.h>
  17. namespace GUI::GML {
  18. static ErrorOr<NonnullRefPtr<Object>> parse_gml_object(Queue<Token>& tokens)
  19. {
  20. auto object = TRY(try_make_ref_counted<Object>());
  21. auto peek = [&] {
  22. if (tokens.is_empty())
  23. return Token::Type::Unknown;
  24. return tokens.head().m_type;
  25. };
  26. while (peek() == Token::Type::Comment)
  27. TRY(object->add_property_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
  28. if (peek() != Token::Type::ClassMarker)
  29. return Error::from_string_literal("Expected class marker");
  30. tokens.dequeue();
  31. if (peek() != Token::Type::ClassName)
  32. return Error::from_string_literal("Expected class name");
  33. auto class_name = tokens.dequeue();
  34. object->set_name(class_name.m_view);
  35. if (peek() == Token::Type::LeftCurly) {
  36. tokens.dequeue();
  37. NonnullRefPtrVector<Comment> pending_comments;
  38. for (;;) {
  39. if (peek() == Token::Type::RightCurly) {
  40. // End of object
  41. break;
  42. }
  43. if (peek() == Token::Type::ClassMarker) {
  44. // It's a child object.
  45. while (!pending_comments.is_empty())
  46. TRY(object->add_sub_object_child(pending_comments.take_first()));
  47. TRY(object->add_sub_object_child(TRY(parse_gml_object(tokens))));
  48. } else if (peek() == Token::Type::Identifier) {
  49. // It's a property.
  50. while (!pending_comments.is_empty())
  51. TRY(object->add_property_child(pending_comments.take_first()));
  52. auto property_name = tokens.dequeue();
  53. if (property_name.m_view.is_empty())
  54. return Error::from_string_literal("Expected non-empty property name");
  55. if (peek() != Token::Type::Colon)
  56. return Error::from_string_literal("Expected ':'");
  57. tokens.dequeue();
  58. RefPtr<ValueNode> value;
  59. if (peek() == Token::Type::ClassMarker)
  60. value = TRY(parse_gml_object(tokens));
  61. else if (peek() == Token::Type::JsonValue)
  62. value = TRY(try_make_ref_counted<JsonValueNode>(TRY(JsonValueNode::from_string(tokens.dequeue().m_view))));
  63. auto property = TRY(try_make_ref_counted<KeyValuePair>(property_name.m_view, value.release_nonnull()));
  64. TRY(object->add_property_child(property));
  65. } else if (peek() == Token::Type::Comment) {
  66. pending_comments.append(TRY(Node::from_token<Comment>(tokens.dequeue())));
  67. } else {
  68. return Error::from_string_literal("Expected child, property, comment, or }}");
  69. }
  70. }
  71. // Insert any left-over comments as sub object children, as these will be serialized last
  72. while (!pending_comments.is_empty())
  73. TRY(object->add_sub_object_child(pending_comments.take_first()));
  74. if (peek() != Token::Type::RightCurly)
  75. return Error::from_string_literal("Expected }}");
  76. tokens.dequeue();
  77. }
  78. return object;
  79. }
  80. ErrorOr<NonnullRefPtr<GMLFile>> parse_gml(StringView string)
  81. {
  82. auto lexer = Lexer(string);
  83. Queue<Token> tokens;
  84. for (auto& token : lexer.lex())
  85. tokens.enqueue(token);
  86. auto file = TRY(try_make_ref_counted<GMLFile>());
  87. auto peek = [&] {
  88. if (tokens.is_empty())
  89. return Token::Type::Unknown;
  90. return tokens.head().m_type;
  91. };
  92. while (peek() == Token::Type::Comment)
  93. TRY(file->add_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
  94. TRY(file->add_child(TRY(parse_gml_object(tokens))));
  95. while (!tokens.is_empty())
  96. TRY(file->add_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
  97. return file;
  98. }
  99. }