mirror of
https://github.com/RGBCube/serenity
synced 2025-05-14 15:04:59 +00:00
124 lines
4.5 KiB
C++
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/SpecificationParsing.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<SpecificationFunction>(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) {});
|
|
}
|
|
}
|
|
|
|
}
|