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:
parent
e0916dbb35
commit
e6331031c4
Notes:
sideshowbarker
2024-07-17 06:33:00 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e6331031c4 Pull-request: https://github.com/SerenityOS/serenity/pull/16153 Reviewed-by: https://github.com/linusg
11 changed files with 74 additions and 36 deletions
|
@ -31,6 +31,7 @@ set(SOURCES
|
|||
MarkupGenerator.cpp
|
||||
Module.cpp
|
||||
Parser.cpp
|
||||
ParserError.cpp
|
||||
Runtime/AbstractOperations.cpp
|
||||
Runtime/AggregateError.cpp
|
||||
Runtime/AggregateErrorConstructor.cpp
|
||||
|
|
|
@ -181,6 +181,8 @@ class Intrinsics;
|
|||
class Module;
|
||||
class NativeFunction;
|
||||
class ObjectEnvironment;
|
||||
class Parser;
|
||||
struct ParserError;
|
||||
class PrimitiveString;
|
||||
class PromiseCapability;
|
||||
class PromiseReaction;
|
||||
|
|
|
@ -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;
|
||||
|
|
38
Userland/Libraries/LibJS/ParserError.cpp
Normal file
38
Userland/Libraries/LibJS/ParserError.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
24
Userland/Libraries/LibJS/ParserError.h
Normal file
24
Userland/Libraries/LibJS/ParserError.h
Normal 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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue