mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 06:37:43 +00:00
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
11 changed files with 74 additions and 36 deletions
|
@ -31,6 +31,7 @@ set(SOURCES
|
||||||
MarkupGenerator.cpp
|
MarkupGenerator.cpp
|
||||||
Module.cpp
|
Module.cpp
|
||||||
Parser.cpp
|
Parser.cpp
|
||||||
|
ParserError.cpp
|
||||||
Runtime/AbstractOperations.cpp
|
Runtime/AbstractOperations.cpp
|
||||||
Runtime/AggregateError.cpp
|
Runtime/AggregateError.cpp
|
||||||
Runtime/AggregateErrorConstructor.cpp
|
Runtime/AggregateErrorConstructor.cpp
|
||||||
|
|
|
@ -181,6 +181,8 @@ class Intrinsics;
|
||||||
class Module;
|
class Module;
|
||||||
class NativeFunction;
|
class NativeFunction;
|
||||||
class ObjectEnvironment;
|
class ObjectEnvironment;
|
||||||
|
class Parser;
|
||||||
|
struct ParserError;
|
||||||
class PrimitiveString;
|
class PrimitiveString;
|
||||||
class PromiseCapability;
|
class PromiseCapability;
|
||||||
class PromiseReaction;
|
class PromiseReaction;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <LibJS/AST.h>
|
#include <LibJS/AST.h>
|
||||||
#include <LibJS/Lexer.h>
|
#include <LibJS/Lexer.h>
|
||||||
|
#include <LibJS/ParserError.h>
|
||||||
#include <LibJS/Runtime/FunctionConstructor.h>
|
#include <LibJS/Runtime/FunctionConstructor.h>
|
||||||
#include <LibJS/SourceRange.h>
|
#include <LibJS/SourceRange.h>
|
||||||
#include <LibJS/Token.h>
|
#include <LibJS/Token.h>
|
||||||
|
@ -173,36 +174,8 @@ public:
|
||||||
|
|
||||||
Vector<CallExpression::Argument> parse_arguments();
|
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(); }
|
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
|
void print_errors(bool print_hint = true) const
|
||||||
{
|
{
|
||||||
for (auto& error : m_state.errors) {
|
for (auto& error : m_state.errors) {
|
||||||
|
@ -305,7 +278,7 @@ private:
|
||||||
struct ParserState {
|
struct ParserState {
|
||||||
Lexer lexer;
|
Lexer lexer;
|
||||||
Token current_token;
|
Token current_token;
|
||||||
Vector<Error> errors;
|
Vector<ParserError> errors;
|
||||||
ScopePusher* current_scope_pusher { nullptr };
|
ScopePusher* current_scope_pusher { nullptr };
|
||||||
|
|
||||||
HashMap<StringView, Optional<Position>> labels_in_scope;
|
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 {
|
namespace JS {
|
||||||
|
|
||||||
// 16.1.5 ParseScript ( sourceText, realm, hostDefined ), https://tc39.es/ecma262/#sec-parse-script
|
// 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).
|
// 1. Let script be ParseText(sourceText, Script).
|
||||||
auto parser = Parser(Lexer(source_text, filename, line_number_offset));
|
auto parser = Parser(Lexer(source_text, filename, line_number_offset));
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Script() override;
|
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; }
|
Realm& realm() { return *m_realm; }
|
||||||
Program const& parse_node() const { return *m_parse_node; }
|
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
|
// 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).
|
// 1. Let body be ParseText(sourceText, Module).
|
||||||
auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);
|
auto parser = Parser(Lexer(source_text, filename), Program::Type::Module);
|
||||||
|
|
|
@ -20,7 +20,7 @@ class SourceTextModule final : public CyclicModule {
|
||||||
JS_CELL(SourceTextModule, CyclicModule);
|
JS_CELL(SourceTextModule, CyclicModule);
|
||||||
|
|
||||||
public:
|
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; }
|
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;
|
extern HashMap<bool*, Tuple<String, String, char>> g_extra_args;
|
||||||
|
|
||||||
struct ParserError {
|
struct ParserError {
|
||||||
JS::Parser::Error error;
|
JS::ParserError error;
|
||||||
String hint;
|
String hint;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ private:
|
||||||
|
|
||||||
JS::GCPtr<JS::Script> m_script_record;
|
JS::GCPtr<JS::Script> m_script_record;
|
||||||
MutedErrors m_muted_errors { MutedErrors::No };
|
MutedErrors m_muted_errors { MutedErrors::No };
|
||||||
Optional<JS::Parser::Error> m_error_to_rethrow;
|
Optional<JS::ParserError> m_error_to_rethrow;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue