1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-16 10:24:59 +00:00

JSSpecCompiler: Mostly get rid of ParseError in AlgorithmStep

And while on it, create proper logical scopes for algorithm steps.
This commit is contained in:
Dan Klishch 2024-01-16 22:16:39 -05:00 committed by Andrew Kaster
parent 1bd1187c92
commit cb6e75e890
2 changed files with 79 additions and 12 deletions

View file

@ -33,6 +33,18 @@ LogicalLocation& SpecificationParsingContext::current_logical_scope()
return *m_current_logical_scope; return *m_current_logical_scope;
} }
template<typename Func>
auto SpecificationParsingContext::with_new_step_list_nesting_level(Func&& func)
{
TemporaryChange change(m_step_list_nesting_level, m_step_list_nesting_level + 1);
return func();
}
int SpecificationParsingContext::step_list_nesting_level() const
{
return m_step_list_nesting_level;
}
Location SpecificationParsingContext::file_scope() const Location SpecificationParsingContext::file_scope() const
{ {
return { .filename = m_translation_unit->filename() }; return { .filename = m_translation_unit->filename() };
@ -48,20 +60,38 @@ Location SpecificationParsingContext::location_from_xml_offset(XML::Offset offse
}; };
} }
ParseErrorOr<AlgorithmStep> AlgorithmStep::create(SpecificationParsingContext& ctx, XML::Node const* node) Optional<AlgorithmStep> AlgorithmStep::create(SpecificationParsingContext& ctx, XML::Node const* element)
{ {
VERIFY(node->as_element().name == tag_li); VERIFY(element->as_element().name == tag_li);
auto [tokens, substeps] = TRY(tokenize_tree(node, true)); auto tokenization_result = tokenize_tree(element, true);
AlgorithmStep result { .m_tokens = move(tokens), .m_node = node }; if (tokenization_result.is_error()) {
ctx.diag().error(ctx.location_from_xml_offset(tokenization_result.error()->offset()),
"{}", tokenization_result.error()->to_string());
return {};
}
auto [tokens, substeps] = tokenization_result.release_value();
AlgorithmStep result { .m_tokens = move(tokens), .m_node = element };
if (substeps) { if (substeps) {
auto step_list = AlgorithmStepList::create(ctx, substeps); // FIXME: Remove this once macOS Lagom CI updates to Clang >= 16.
auto substeps_copy = substeps;
auto step_list = ctx.with_new_step_list_nesting_level([&] {
return AlgorithmStepList::create(ctx, substeps_copy);
});
if (step_list.has_value()) if (step_list.has_value())
result.m_substeps = step_list->m_expression; result.m_substeps = step_list->m_expression;
} }
result.m_expression = TRY(result.parse()); auto parse_result = result.parse();
if (parse_result.is_error()) {
ctx.diag().error(ctx.location_from_xml_offset(parse_result.error()->offset()),
"{}", parse_result.error()->to_string());
return {};
}
result.m_expression = parse_result.release_value();
return result; return result;
} }
@ -84,21 +114,25 @@ Optional<AlgorithmStepList> AlgorithmStepList::create(SpecificationParsingContex
Vector<Tree> step_expressions; Vector<Tree> step_expressions;
bool all_steps_parsed = true; bool all_steps_parsed = true;
int step_number = 0;
auto const& parent_scope = ctx.current_logical_scope();
for (auto const& child : element->as_element().children) { for (auto const& child : element->as_element().children) {
child->content.visit( child->content.visit(
[&](XML::Node::Element const& element) { [&](XML::Node::Element const& element) {
if (element.name == tag_li) { if (element.name == tag_li) {
auto step_creation_result = AlgorithmStep::create(ctx, child); auto step_creation_result = ctx.with_new_logical_scope([&] {
if (step_creation_result.is_error()) { update_logical_scope_for_step(ctx, parent_scope, step_number);
// TODO: Integrate backtracing parser errors better return AlgorithmStep::create(ctx, child);
ctx.diag().error(ctx.location_from_xml_offset(step_creation_result.error()->offset()), });
"{}", step_creation_result.error()->to_string()); if (!step_creation_result.has_value()) {
all_steps_parsed = false; all_steps_parsed = false;
} else { } else {
steps.append(step_creation_result.release_value()); steps.append(step_creation_result.release_value());
step_expressions.append(steps.last().m_expression); step_expressions.append(steps.last().m_expression);
} }
++step_number;
return; return;
} }
@ -121,6 +155,31 @@ Optional<AlgorithmStepList> AlgorithmStepList::create(SpecificationParsingContex
return result; return result;
} }
void AlgorithmStepList::update_logical_scope_for_step(SpecificationParsingContext& ctx, LogicalLocation const& parent_scope, int step_number)
{
int nesting_level = ctx.step_list_nesting_level();
String list_step_number;
if (nesting_level == 0 || nesting_level == 3) {
list_step_number = MUST(String::formatted("{}", step_number + 1));
} else if (nesting_level == 1 || nesting_level == 4) {
if (step_number < 26)
list_step_number = String::from_code_point('a' + step_number);
else
list_step_number = MUST(String::formatted("{}", step_number + 1));
} else {
list_step_number = MUST(String::from_byte_string(ByteString::roman_number_from(step_number + 1).to_lowercase()));
}
auto& scope = ctx.current_logical_scope();
scope.section = parent_scope.section;
if (parent_scope.step.is_empty())
scope.step = list_step_number;
else
scope.step = MUST(String::formatted("{}.{}", parent_scope.step, list_step_number));
}
Optional<Algorithm> Algorithm::create(SpecificationParsingContext& ctx, XML::Node const* element) Optional<Algorithm> Algorithm::create(SpecificationParsingContext& ctx, XML::Node const* element)
{ {
VERIFY(element->as_element().name == tag_emu_alg); VERIFY(element->as_element().name == tag_emu_alg);

View file

@ -33,12 +33,17 @@ public:
auto with_new_logical_scope(Func&& func); auto with_new_logical_scope(Func&& func);
LogicalLocation& current_logical_scope(); LogicalLocation& current_logical_scope();
template<typename Func>
auto with_new_step_list_nesting_level(Func&& func);
int step_list_nesting_level() const;
Location file_scope() const; Location file_scope() const;
Location location_from_xml_offset(XML::Offset offset) const; Location location_from_xml_offset(XML::Offset offset) const;
private: private:
TranslationUnitRef m_translation_unit; TranslationUnitRef m_translation_unit;
RefPtr<LogicalLocation> m_current_logical_scope; RefPtr<LogicalLocation> m_current_logical_scope;
int m_step_list_nesting_level = 0;
}; };
class AlgorithmStepList { class AlgorithmStepList {
@ -47,11 +52,14 @@ public:
Vector<AlgorithmStep> m_steps; Vector<AlgorithmStep> m_steps;
Tree m_expression = error_tree; Tree m_expression = error_tree;
private:
static void update_logical_scope_for_step(SpecificationParsingContext& ctx, LogicalLocation const& parent_scope, int step_number);
}; };
class AlgorithmStep { class AlgorithmStep {
public: public:
static ParseErrorOr<AlgorithmStep> create(SpecificationParsingContext& ctx, XML::Node const* node); static Optional<AlgorithmStep> create(SpecificationParsingContext& ctx, XML::Node const* node);
ParseErrorOr<Tree> parse(); ParseErrorOr<Tree> parse();