diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 94bf21ccc1..ddf2297306 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -39,7 +39,7 @@ HashMap Lexer::s_single_char_tokens; Lexer::Lexer(StringView source) : m_source(source) - , m_current_token(TokenType::Eof, StringView(nullptr), StringView(nullptr)) + , m_current_token(TokenType::Eof, StringView(nullptr), StringView(nullptr), 0, 0) { if (s_keywords.is_empty()) { s_keywords.set("await", TokenType::Await); @@ -146,6 +146,13 @@ void Lexer::consume() return; } + if (m_current_char == '\n') { + m_line_number++; + m_line_column = 1; + } else { + m_line_column++; + } + m_current_char = m_source[m_position++]; } @@ -182,7 +189,7 @@ bool Lexer::is_block_comment_end() const void Lexer::syntax_error(const char* msg) { m_has_errors = true; - fprintf(stderr, "Syntax Error: %s\n", msg); + fprintf(stderr, "Syntax Error: %s (line: %zu, column: %zu)\n", msg, m_line_number, m_line_column); } Token Lexer::next() @@ -317,7 +324,9 @@ Token Lexer::next() m_current_token = Token( token_type, m_source.substring_view(trivia_start - 1, value_start - trivia_start), - m_source.substring_view(value_start - 1, m_position - value_start)); + m_source.substring_view(value_start - 1, m_position - value_start), + m_line_number, + m_line_column); return m_current_token; } diff --git a/Libraries/LibJS/Lexer.h b/Libraries/LibJS/Lexer.h index 887ef040aa..9bc286190e 100644 --- a/Libraries/LibJS/Lexer.h +++ b/Libraries/LibJS/Lexer.h @@ -54,8 +54,10 @@ private: StringView m_source; size_t m_position = 0; Token m_current_token; - int m_current_char; + int m_current_char = 0; bool m_has_errors = false; + size_t m_line_number = 1; + size_t m_line_column = 1; static HashMap s_keywords; static HashMap s_three_char_tokens; diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 4b074eb7e5..3f91503421 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -967,7 +967,12 @@ Token Parser::consume(TokenType type) { if (m_parser_state.m_current_token.type() != type) { m_parser_state.m_has_errors = true; - fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_parser_state.m_current_token.name(), Token::name(type)); + auto& current_token = m_parser_state.m_current_token; + fprintf(stderr, "Error: Unexpected token %s. Expected %s (line: %zu, column: %zu))\n", + current_token.name(), + Token::name(type), + current_token.line_number(), + current_token.line_column()); } return consume(); } @@ -975,7 +980,12 @@ Token Parser::consume(TokenType type) void Parser::expected(const char* what) { m_parser_state.m_has_errors = true; - fprintf(stderr, "Error: Unexpected token %s. Expected %s\n", m_parser_state.m_current_token.name(), what); + auto& current_token = m_parser_state.m_current_token; + fprintf(stderr, "Error: Unexpected token %s. Expected %s (line: %zu, column: %zu)\n", + current_token.name(), + what, + current_token.line_number(), + current_token.line_column()); } void Parser::save_state() diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index cbd8c5199a..ac442136ad 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -131,10 +131,12 @@ enum class TokenType { class Token { public: - Token(TokenType type, StringView trivia, StringView value) + Token(TokenType type, StringView trivia, StringView value, size_t line_number, size_t line_column) : m_type(type) , m_trivia(trivia) , m_value(value) + , m_line_number(line_number) + , m_line_column(line_column) { } @@ -144,6 +146,8 @@ public: const StringView& trivia() const { return m_trivia; } const StringView& value() const { return m_value; } + size_t line_number() const { return m_line_number; } + size_t line_column() const { return m_line_column; } double double_value() const; String string_value() const; bool bool_value() const; @@ -152,6 +156,8 @@ private: TokenType m_type; StringView m_trivia; StringView m_value; + size_t m_line_number; + size_t m_line_column; }; }