LibJS: Make Parser::Error a standalone ParserError class

This allows us to forward declare it and reduce the number of things
that need to include Parser.h.
This commit is contained in:
Andreas Kling 2022-11-23 12:39:23 +01:00 committed by Linus Groh
parent e0916dbb35
commit e6331031c4
Notes: sideshowbarker 2024-07-17 06:33:00 +09:00
11 changed files with 74 additions and 36 deletions

View file

@ -31,6 +31,7 @@ set(SOURCES
MarkupGenerator.cpp
Module.cpp
Parser.cpp
ParserError.cpp
Runtime/AbstractOperations.cpp
Runtime/AggregateError.cpp
Runtime/AggregateErrorConstructor.cpp

View file

@ -181,6 +181,8 @@ class Intrinsics;
class Module;
class NativeFunction;
class ObjectEnvironment;
class Parser;
struct ParserError;
class PrimitiveString;
class PromiseCapability;
class PromiseReaction;

View file

@ -13,6 +13,7 @@
#include <AK/StringBuilder.h>
#include <LibJS/AST.h>
#include <LibJS/Lexer.h>
#include <LibJS/ParserError.h>
#include <LibJS/Runtime/FunctionConstructor.h>
#include <LibJS/SourceRange.h>
#include <LibJS/Token.h>
@ -173,36 +174,8 @@ public:
Vector<CallExpression::Argument> parse_arguments();
struct Error {
String message;
Optional<Position> position;
String to_string() const
{
if (!position.has_value())
return message;
return String::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column);
}
String source_location_hint(StringView source, char const spacer = ' ', char const indicator = '^') const
{
if (!position.has_value())
return {};
// We need to modify the source to match what the lexer considers one line - normalizing
// line terminators to \n is easier than splitting using all different LT characters.
String source_string = source.replace("\r\n"sv, "\n"sv, ReplaceMode::All).replace("\r"sv, "\n"sv, ReplaceMode::All).replace(LINE_SEPARATOR_STRING, "\n"sv, ReplaceMode::All).replace(PARAGRAPH_SEPARATOR_STRING, "\n"sv, ReplaceMode::All);
StringBuilder builder;
builder.append(source_string.split_view('\n', SplitBehavior::KeepEmpty)[position.value().line - 1]);
builder.append('\n');
for (size_t i = 0; i < position.value().column - 1; ++i)
builder.append(spacer);
builder.append(indicator);
return builder.build();
}
};
bool has_errors() const { return m_state.errors.size(); }
Vector<Error> const& errors() const { return m_state.errors; }
Vector<ParserError> const& errors() const { return m_state.errors; }
void print_errors(bool print_hint = true) const
{
for (auto& error : m_state.errors) {
@ -305,7 +278,7 @@ private:
struct ParserState {
Lexer lexer;
Token current_token;
Vector<Error> errors;
Vector<ParserError> errors;
ScopePusher* current_scope_pusher { nullptr };
HashMap<StringView, Optional<Position>> labels_in_scope;

View file

@ -0,0 +1,38 @@
/*
* Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
* Copyright (c) 2021-2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/StringView.h>
#include <AK/Vector.h>
#include <LibJS/ParserError.h>
#include <LibJS/Token.h>
namespace JS {
String ParserError::to_string() const
{
if (!position.has_value())
return message;
return String::formatted("{} (line: {}, column: {})", message, position.value().line, position.value().column);
}
String ParserError::source_location_hint(StringView source, char const spacer, char const indicator) const
{
if (!position.has_value())
return {};
// We need to modify the source to match what the lexer considers one line - normalizing
// line terminators to \n is easier than splitting using all different LT characters.
String source_string = source.replace("\r\n"sv, "\n"sv, ReplaceMode::All).replace("\r"sv, "\n"sv, ReplaceMode::All).replace(LINE_SEPARATOR_STRING, "\n"sv, ReplaceMode::All).replace(PARAGRAPH_SEPARATOR_STRING, "\n"sv, ReplaceMode::All);
StringBuilder builder;
builder.append(source_string.split_view('\n', SplitBehavior::KeepEmpty)[position.value().line - 1]);
builder.append('\n');
for (size_t i = 0; i < position.value().column - 1; ++i)
builder.append(spacer);
builder.append(indicator);
return builder.build();
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2020, Stephan Unverwerth <s.unverwerth@serenityos.org>
* Copyright (c) 2021-2022, David Tuin <davidot@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Optional.h>
#include <AK/String.h>
#include <LibJS/SourceRange.h>
namespace JS {
struct ParserError {
String message;
Optional<Position> position;
String to_string() const;
String source_location_hint(StringView source, char const spacer = ' ', char const indicator = '^') const;
};
}

View file

@ -13,7 +13,7 @@
namespace JS {
// 16.1.5 ParseScript ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parse-script
Result<NonnullGCPtr<Script>, Vector<Parser::Error>> Script::parse(StringView source_text, Realm& realm, StringView filename, HostDefined* host_defined, size_t line_number_offset)
Result<NonnullGCPtr<Script>, Vector<ParserError>> Script::parse(StringView source_text, Realm& realm, StringView filename, HostDefined* host_defined, size_t line_number_offset)
{
// 1. Let script be ParseText(sourceText, Script).
auto parser = Parser(Lexer(source_text, filename, line_number_offset));

View file

@ -27,7 +27,7 @@ public:
};
virtual ~Script() override;
static Result<NonnullGCPtr<Script>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {}, HostDefined* = nullptr, size_t line_number_offset = 1);
static Result<NonnullGCPtr<Script>, Vector<ParserError>> parse(StringView source_text, Realm&, StringView filename = {}, HostDefined* = nullptr, size_t line_number_offset = 1);
Realm& realm() { return *m_realm; }
Program const& parse_node() const { return *m_parse_node; }

View file

@ -120,7 +120,7 @@ void SourceTextModule::visit_edges(Cell::Visitor& visitor)
}
// 16.2.1.6.1 ParseModule ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parsemodule
Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
Result<NonnullGCPtr<SourceTextModule>, Vector<ParserError>> SourceTextModule::parse(StringView source_text, Realm& realm, StringView filename, Script::HostDefined* host_defined)
{
// 1. Let body be ParseText(sourceText, Module).
auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);

View file

@ -20,7 +20,7 @@ class SourceTextModule final : public CyclicModule {
JS_CELL(SourceTextModule, CyclicModule);
public:
static Result<NonnullGCPtr<SourceTextModule>, Vector<Parser::Error>> parse(StringView source_text, Realm&, StringView filename = {}, Script::HostDefined* host_defined = nullptr);
static Result<NonnullGCPtr<SourceTextModule>, Vector<ParserError>> parse(StringView source_text, Realm&, StringView filename = {}, Script::HostDefined* host_defined = nullptr);
Program const& parse_node() const { return *m_ecmascript_code; }

View file

@ -143,7 +143,7 @@ extern Function<NonnullOwnPtr<JS::Interpreter>()> g_create_interpreter_hook;
extern HashMap<bool*, Tuple<String, String, char>> g_extra_args;
struct ParserError {
JS::Parser::Error error;
JS::ParserError error;
String hint;
};

View file

@ -43,7 +43,7 @@ private:
JS::GCPtr<JS::Script> m_script_record;
MutedErrors m_muted_errors { MutedErrors::No };
Optional<JS::Parser::Error> m_error_to_rethrow;
Optional<JS::ParserError> m_error_to_rethrow;
};
}