123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- /*
- * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2022, kleines Filmröllchen <filmroellchen@serenityos.org>
- * Copyright (c) 2022, Idan Horowitz <idan.horowitz@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include "Parser.h"
- #include "AST.h"
- #include "Lexer.h"
- #include <AK/Error.h>
- #include <AK/GenericLexer.h>
- #include <AK/JsonObject.h>
- #include <AK/JsonValue.h>
- #include <AK/Queue.h>
- #include <AK/RefPtr.h>
- namespace GUI::GML {
- static ErrorOr<NonnullRefPtr<Object>> parse_gml_object(Queue<Token>& tokens)
- {
- auto object = TRY(try_make_ref_counted<Object>());
- auto peek = [&] {
- if (tokens.is_empty())
- return Token::Type::Unknown;
- return tokens.head().m_type;
- };
- while (peek() == Token::Type::Comment)
- TRY(object->add_property_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
- if (peek() != Token::Type::ClassMarker)
- return Error::from_string_literal("Expected class marker"sv);
- tokens.dequeue();
- if (peek() != Token::Type::ClassName)
- return Error::from_string_literal("Expected class name"sv);
- auto class_name = tokens.dequeue();
- object->set_name(class_name.m_view);
- if (peek() != Token::Type::LeftCurly)
- return Error::from_string_literal("Expected {{"sv);
- tokens.dequeue();
- NonnullRefPtrVector<Comment> pending_comments;
- for (;;) {
- if (peek() == Token::Type::RightCurly) {
- // End of object
- break;
- }
- if (peek() == Token::Type::ClassMarker) {
- // It's a child object.
- while (!pending_comments.is_empty())
- TRY(object->add_sub_object_child(pending_comments.take_first()));
- TRY(object->add_sub_object_child(TRY(parse_gml_object(tokens))));
- } else if (peek() == Token::Type::Identifier) {
- // It's a property.
- while (!pending_comments.is_empty())
- TRY(object->add_property_child(pending_comments.take_first()));
- auto property_name = tokens.dequeue();
- if (property_name.m_view.is_empty())
- return Error::from_string_literal("Expected non-empty property name"sv);
- if (peek() != Token::Type::Colon)
- return Error::from_string_literal("Expected ':'"sv);
- tokens.dequeue();
- RefPtr<ValueNode> value;
- if (peek() == Token::Type::ClassMarker)
- value = TRY(parse_gml_object(tokens));
- else if (peek() == Token::Type::JsonValue)
- value = TRY(try_make_ref_counted<JsonValueNode>(TRY(JsonValueNode::from_string(tokens.dequeue().m_view))));
- auto property = TRY(try_make_ref_counted<KeyValuePair>(property_name.m_view, value.release_nonnull()));
- TRY(object->add_property_child(property));
- } else if (peek() == Token::Type::Comment) {
- pending_comments.append(TRY(Node::from_token<Comment>(tokens.dequeue())));
- } else {
- return Error::from_string_literal("Expected child, property, comment, or }}"sv);
- }
- }
- // Insert any left-over comments as sub object children, as these will be serialized last
- while (!pending_comments.is_empty())
- TRY(object->add_sub_object_child(pending_comments.take_first()));
- if (peek() != Token::Type::RightCurly)
- return Error::from_string_literal("Expected }}"sv);
- tokens.dequeue();
- return object;
- }
- ErrorOr<NonnullRefPtr<GMLFile>> parse_gml(StringView string)
- {
- auto lexer = Lexer(string);
- Queue<Token> tokens;
- for (auto& token : lexer.lex())
- tokens.enqueue(token);
- auto file = TRY(try_make_ref_counted<GMLFile>());
- auto peek = [&] {
- if (tokens.is_empty())
- return Token::Type::Unknown;
- return tokens.head().m_type;
- };
- while (peek() == Token::Type::Comment)
- TRY(file->add_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
- TRY(file->add_child(TRY(parse_gml_object(tokens))));
- while (!tokens.is_empty())
- TRY(file->add_child(TRY(Node::from_token<Comment>(tokens.dequeue()))));
- return file;
- }
- }
|