1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 22:34:59 +00:00
serenity/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Parser/SpecificationClause.cpp
Dan Klishch 7ea2138b6c JSSpecCompiler: Split Parser/SpecParser.cpp into 8 files
This SpecParser.cpp had an ever increasing number of lines and contained
an implementation of 8 different classes. So I figured out it's about
the time to split it.

No behavior change.
2024-03-14 18:34:13 -06:00

124 lines
4.5 KiB
C++

/*
* Copyright (c) 2023-2024, Dan Klishch <danilklishch@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Parser/Lexer.h"
#include "Parser/SpecParser.h"
#include "Parser/XMLUtils.h"
namespace JSSpecCompiler {
NonnullOwnPtr<SpecificationClause> SpecificationClause::create(SpecificationParsingContext& ctx, XML::Node const* element)
{
return ctx.with_new_logical_scope([&] {
VERIFY(element->as_element().name == tag_emu_clause);
SpecificationClause specification_clause(ctx);
specification_clause.parse(element);
OwnPtr<SpecificationClause> result;
specification_clause.m_header.header.visit(
[&](AK::Empty const&) {
result = make<SpecificationClause>(move(specification_clause));
},
[&](OneOf<ClauseHeader::AbstractOperation, ClauseHeader::Accessor, ClauseHeader::Method> auto const&) {
result = make<SpecFunction>(move(specification_clause));
});
if (!result->post_initialize(element))
result = make<SpecificationClause>(move(*result));
return result.release_nonnull();
});
}
void SpecificationClause::collect_into(TranslationUnitRef translation_unit)
{
do_collect(translation_unit);
for (auto& subclause : m_subclauses)
subclause->collect_into(translation_unit);
}
Optional<FailedTextParseDiagnostic> SpecificationClause::parse_header(XML::Node const* element)
{
auto& ctx = *m_ctx_pointer;
VERIFY(element->as_element().name == tag_h1);
auto maybe_tokens = tokenize_header(ctx, element);
if (!maybe_tokens.has_value())
return {};
auto const& tokens = maybe_tokens.release_value();
TextParser parser(ctx, tokens, element);
auto parse_result = parser.parse_clause_header(m_clause_has_aoid_attribute);
if (parse_result.is_error()) {
// Still try to at least scavenge section number.
if (tokens.size() && tokens[0].type == TokenType::SectionNumber)
ctx.current_logical_scope().section = MUST(String::from_utf8(tokens[0].data));
return parser.get_diagnostic();
}
m_header = parse_result.release_value();
ctx.current_logical_scope().section = MUST(String::from_utf8(m_header.section_number));
return {};
}
void SpecificationClause::parse(XML::Node const* element)
{
auto& ctx = context();
u32 child_index = 0;
bool node_ignored_warning_issued = false;
Optional<FailedTextParseDiagnostic> header_parse_error;
m_clause_has_aoid_attribute = element->as_element().attributes.get("aoid").has_value()
? TextParser::ClauseHasAoidAttribute::Yes
: TextParser::ClauseHasAoidAttribute::No;
for (auto const& child : element->as_element().children) {
child->content.visit(
[&](XML::Node::Element const& element) {
if (child_index == 0) {
if (element.name != tag_h1) {
ctx.diag().error(ctx.location_from_xml_offset(child->offset),
"<h1> must be the first child of <emu-clause>");
return;
}
header_parse_error = parse_header(child);
} else {
if (element.name == tag_h1) {
ctx.diag().error(ctx.location_from_xml_offset(child->offset),
"<h1> can only be the first child of <emu-clause>");
return;
}
if (element.name == tag_emu_clause) {
m_subclauses.append(create(ctx, child));
return;
}
if (!node_ignored_warning_issued && m_header.header.has<AK::Empty>()) {
node_ignored_warning_issued = true;
ctx.diag().warn(ctx.location_from_xml_offset(child->offset),
"node content will be ignored since section header was not parsed successfully");
if (header_parse_error.has_value())
ctx.diag().note(header_parse_error->location, "{}", header_parse_error->message);
}
}
++child_index;
},
[&](XML::Node::Text const&) {
if (!contains_empty_text(child)) {
ctx.diag().error(ctx.location_from_xml_offset(child->offset),
"non-empty text node should not be a child of <emu-clause>");
}
},
[&](auto) {});
}
}
}