JSSpecCompiler: Parse accessor property headers

This commit is contained in:
Dan Klishch 2024-01-21 00:10:46 -05:00 committed by Andrew Kaster
parent a9f3a14a13
commit d1fc84c638
Notes: sideshowbarker 2024-07-17 01:00:06 +09:00
4 changed files with 108 additions and 41 deletions

View file

@ -239,7 +239,7 @@ NonnullOwnPtr<SpecificationClause> SpecificationClause::create(SpecificationPars
[&](AK::Empty const&) {
result = make<SpecificationClause>(move(specification_clause));
},
[&](ClauseHeader::FunctionDefinition const&) {
[&](OneOf<ClauseHeader::AbstractOperation, ClauseHeader::Accessor> auto const&) {
result = make<SpecFunction>(move(specification_clause));
});
@ -346,18 +346,26 @@ bool SpecFunction::post_initialize(XML::Node const* element)
m_id = maybe_id.value();
}
auto maybe_abstract_operation_id = get_attribute_by_name(element, attribute_aoid);
if (maybe_abstract_operation_id.has_value())
m_name = maybe_abstract_operation_id.value();
m_header.header.visit(
[&](ClauseHeader::AbstractOperation const& abstract_operation) {
auto maybe_abstract_operation_id = get_attribute_by_name(element, attribute_aoid);
if (maybe_abstract_operation_id.has_value())
m_name = MUST(String::from_utf8(maybe_abstract_operation_id.value()));
m_section_number = m_header.section_number;
auto const& [function_name, arguments] = m_header.header.get<ClauseHeader::FunctionDefinition>();
m_arguments = arguments;
auto const& [function_name, arguments] = abstract_operation;
m_arguments = arguments;
if (m_name != function_name) {
ctx.diag().warn(ctx.location_from_xml_offset(element->offset),
"function name in header and <emu-clause>[aoid] do not match");
}
if (m_name != function_name) {
ctx.diag().warn(ctx.location_from_xml_offset(element->offset),
"function name in header and <emu-clause>[aoid] do not match");
}
},
[&](ClauseHeader::Accessor const& accessor) {
m_name = MUST(String::formatted("%get {}%", MUST(String::join("."sv, accessor.qualified_name))));
},
[&](auto const&) {
VERIFY_NOT_REACHED();
});
Vector<XML::Node const*> algorithm_nodes;
@ -399,12 +407,12 @@ void SpecFunction::do_collect(TranslationUnitRef translation_unit)
translation_unit->adopt_function(make_ref_counted<FunctionDefinition>(m_name, m_algorithm.tree(), move(m_arguments)));
}
Specification Specification::create(SpecificationParsingContext& ctx, XML::Node const* element)
NonnullOwnPtr<Specification> Specification::create(SpecificationParsingContext& ctx, XML::Node const* element)
{
VERIFY(element->as_element().name == tag_specification);
Specification specification;
specification.parse(ctx, element);
auto specification = make<Specification>();
specification->parse(ctx, element);
return specification;
}
@ -486,7 +494,7 @@ void SpecParsingStep::run(TranslationUnitRef translation_unit)
return;
}
auto specification = Specification::create(ctx, &root);
specification.collect_into(translation_unit);
m_specification = Specification::create(ctx, &root);
m_specification->collect_into(translation_unit);
}
}

View file

@ -132,9 +132,8 @@ protected:
void do_collect(TranslationUnitRef translation_unit) override;
private:
StringView m_section_number;
StringView m_id;
StringView m_name;
String m_name;
Vector<FunctionArgument> m_arguments;
Algorithm m_algorithm;
@ -142,7 +141,7 @@ private:
class Specification {
public:
static Specification create(SpecificationParsingContext& ctx, XML::Node const* element);
static NonnullOwnPtr<Specification> create(SpecificationParsingContext& ctx, XML::Node const* element);
void collect_into(TranslationUnitRef translation_unit);
@ -161,6 +160,8 @@ public:
private:
OwnPtr<XML::Document> m_document;
OwnPtr<Specification> m_specification;
ByteBuffer m_input;
};

View file

@ -599,6 +599,69 @@ TextParseErrorOr<Tree> TextParser::parse_step_with_substeps(Tree substeps)
return TextParseError {};
}
// <qualified_name> :== <word> (. <word>)*
TextParseErrorOr<Vector<StringView>> TextParser::parse_qualified_name()
{
Vector<StringView> qualified_name;
qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data);
while (true) {
auto token_or_error = consume_token_with_type(TokenType::MemberAccess);
if (token_or_error.is_error())
return qualified_name;
qualified_name.append(TRY(consume_token_with_type(TokenType::Word)).data);
}
}
// <function_arguments> :== '(' (<word> (, <word>)*)? ')'
TextParseErrorOr<Vector<FunctionArgument>> TextParser::parse_function_arguments_in_declaration()
{
Vector<FunctionArgument> arguments;
TRY(consume_token_with_type(TokenType::ParenOpen));
while (true) {
if (arguments.is_empty()) {
auto argument = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Identifier }));
if (argument.type == TokenType::ParenClose)
break;
arguments.append({ argument.data });
} else {
arguments.append({ TRY(consume_token_with_type(TokenType::Identifier)).data });
}
auto next_token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma }));
if (next_token.type == TokenType::ParenClose)
break;
}
return arguments;
}
// <ao_declaration> :== <word> <function_arguments> $
TextParseErrorOr<ClauseHeader::AbstractOperation> TextParser::parse_abstract_operation_declaration()
{
auto rollback = rollback_point();
ClauseHeader::AbstractOperation function_definition;
function_definition.name = TRY(consume_token_with_type(TokenType::Word)).data;
function_definition.arguments = TRY(parse_function_arguments_in_declaration());
TRY(expect_eof());
rollback.disarm();
return function_definition;
}
// <accessor_declaration> :== get <qualified_name> $
TextParseErrorOr<ClauseHeader::Accessor> TextParser::parse_accessor_declaration()
{
auto rollback = rollback_point();
TRY(consume_word("get"sv));
ClauseHeader::Accessor accessor;
accessor.qualified_name = TRY(parse_qualified_name());
TRY(expect_eof());
rollback.disarm();
return accessor;
}
// <clause_header> :== <section_number> <ao_declaration> | <accessor_declaration>
TextParseErrorOr<ClauseHeader> TextParser::parse_clause_header()
{
ClauseHeader result;
@ -606,27 +669,13 @@ TextParseErrorOr<ClauseHeader> TextParser::parse_clause_header()
auto section_number_token = TRY(consume_token_with_type(TokenType::SectionNumber));
result.section_number = section_number_token.data;
ClauseHeader::FunctionDefinition function_definition;
function_definition.name = TRY(consume_token_with_type(TokenType::Word)).data;
TRY(consume_token_with_type(TokenType::ParenOpen));
while (true) {
if (function_definition.arguments.is_empty()) {
auto argument = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Identifier }));
if (argument.type == TokenType::ParenClose)
break;
function_definition.arguments.append({ argument.data });
} else {
function_definition.arguments.append({ TRY(consume_token_with_type(TokenType::Identifier)).data });
}
auto next_token = TRY(consume_token_with_one_of_types({ TokenType::ParenClose, TokenType::Comma }));
if (next_token.type == TokenType::ParenClose)
break;
if (auto ao_declaration = parse_abstract_operation_declaration(); !ao_declaration.is_error()) {
result.header = ao_declaration.release_value();
} else if (auto accessor = parse_accessor_declaration(); !accessor.is_error()) {
result.header = accessor.release_value();
} else {
return TextParseError {};
}
TRY(expect_eof());
result.header = function_definition;
return result;
}

View file

@ -13,13 +13,17 @@
namespace JSSpecCompiler {
struct ClauseHeader {
struct FunctionDefinition {
struct AbstractOperation {
StringView name;
Vector<FunctionArgument> arguments;
};
struct Accessor {
Vector<StringView> qualified_name;
};
StringView section_number;
Variant<AK::Empty, FunctionDefinition> header;
Variant<AK::Empty, AbstractOperation, Accessor> header;
};
struct TextParseError { };
@ -86,6 +90,11 @@ private:
TextParseErrorOr<Tree> parse_if(Tree then_branch);
TextParseErrorOr<Tree> parse_else(Tree else_branch);
TextParseErrorOr<Vector<StringView>> parse_qualified_name();
TextParseErrorOr<Vector<FunctionArgument>> parse_function_arguments_in_declaration();
TextParseErrorOr<ClauseHeader::AbstractOperation> parse_abstract_operation_declaration();
TextParseErrorOr<ClauseHeader::Accessor> parse_accessor_declaration();
SpecificationParsingContext& m_ctx;
Vector<Token> const& m_tokens;
size_t m_next_token_index = 0;