Skip to content

Commit

Permalink
feat(error.hpp): add line and column info to error message
Browse files Browse the repository at this point in the history
  • Loading branch information
Adamska1008 committed Sep 2, 2024
1 parent cd74648 commit f5d5524
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 30 deletions.
10 changes: 6 additions & 4 deletions include/myxml/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ namespace myxml
std::string message;
// store message after being concated with prefix
mutable std::string fullMessage;
std::size_t line;
std::size_t column;

public:
ParseError(std::string message);
ParseError(std::string message, std::size_t line, std::size_t column);

virtual const char *what() const noexcept override;
};
Expand All @@ -31,7 +33,7 @@ namespace myxml
virtual const char *prefix() const;

public:
SyntaxError(std::string);
SyntaxError(std::string, std::size_t line, std::size_t column);
};

/**
Expand All @@ -43,7 +45,7 @@ namespace myxml
virtual const char *prefix() const;

public:
SemanticError(std::string);
SemanticError(std::string, std::size_t line, std::size_t column);
};

/**
Expand All @@ -55,7 +57,7 @@ namespace myxml
virtual const char *prefix() const;

public:
UnexpectedEndOfInput();
UnexpectedEndOfInput(std::size_t line, std::size_t column);
};

class IOError : public std::exception
Expand Down
1 change: 1 addition & 0 deletions include/myxml/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace myxml
std::optional<char> take();
std::optional<std::string_view> takeN(int);
void skipWhiteSpaces();
std::tuple<std::size_t, std::size_t> currentLoc();

/**
* For all parsing method,
Expand Down
20 changes: 11 additions & 9 deletions src/error.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
#include <fmt/core.h>
#include "myxml/error.hpp"

namespace myxml
{
ParseError::ParseError(std::string message)
: message(message)
ParseError::ParseError(std::string message, std::size_t line, std::size_t column)
: message(message), line(line), column(column)
{
}

const char *ParseError::what() const noexcept
{
this->fullMessage = this->prefix() + this->message;
this->fullMessage = fmt::format("{}{}\nin line: {} column: {}",
this->prefix(), this->message, this->line, this->column);
return this->fullMessage.c_str();
}

Expand All @@ -18,8 +20,8 @@ namespace myxml
return "Syntax Error: ";
}

SyntaxError::SyntaxError(std::string message)
: ParseError(message)
SyntaxError::SyntaxError(std::string, std::size_t line, std::size_t column)
: ParseError(message, line, column)
{
}

Expand All @@ -28,8 +30,8 @@ namespace myxml
return "Sematic Error: ";
}

SemanticError::SemanticError(std::string message)
: ParseError(message)
SemanticError::SemanticError(std::string, std::size_t line, std::size_t column)
: ParseError(message, line, column)
{
}

Expand All @@ -38,8 +40,8 @@ namespace myxml
return "Unexpected End of Input: ";
}

UnexpectedEndOfInput::UnexpectedEndOfInput()
: ParseError("End of input")
UnexpectedEndOfInput::UnexpectedEndOfInput(std::size_t line, std::size_t column)
: ParseError("End of input", line, column)
{
}

Expand Down
58 changes: 41 additions & 17 deletions src/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ namespace myxml
}
}

std::tuple<std::size_t, std::size_t> Parser::currentLoc()
{
return this->buffer->CurrentLocation();
}

std::optional<char> Parser::peek()
{
return this->buffer->Peek();
Expand Down Expand Up @@ -46,11 +51,15 @@ namespace myxml
std::string Parser::parseIdent()
{
if (this->peek() == std::nullopt)
throw UnexpectedEndOfInput();
{
auto [line, col] = this->currentLoc();
throw UnexpectedEndOfInput(line, col);
}
// validate heading character
if (auto head = this->peek(); !head || (!std::isalpha(*head) && head != '_'))
{
throw SyntaxError(fmt::format("element name which starts with {} is invalid.", *head));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("element name which starts with {} is invalid.", *head), line, col);
}
std::size_t len = 0;
while (this->afterN(len) && util::isValidXmlChar(*this->afterN(len)))
Expand All @@ -64,11 +73,13 @@ namespace myxml
{
if (!this->peek())
{
throw UnexpectedEndOfInput();
auto [line, col] = this->currentLoc();
throw UnexpectedEndOfInput(line, col);
}
if (this->peek() != '"')
{
throw SyntaxError(fmt::format("expected '\"' at the beginning of string literal, find {}", *this->peek()));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected '\"' at the beginning of string literal, find {}", *this->peek()), line, col);
}
this->take();
std::size_t len = 0;
Expand All @@ -78,7 +89,8 @@ namespace myxml
}
if (!this->afterN(len))
{ // if jump out due to length limit
throw SyntaxError(fmt::format("missing closing double quote for string literal"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("missing closing double quote for string literal"), line, col);
}
auto it = this->takeN(len);
this->take(); // skip "
Expand All @@ -104,7 +116,8 @@ namespace myxml
}
if (this->take() != '=')
{
throw SyntaxError(fmt::format("expected '=' after attribute name"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected '=' after attribute name"), line, col);
}
attr.first = key;
auto value = this->parseStringLiteral();
Expand All @@ -116,7 +129,8 @@ namespace myxml
{
if (!this->peek())
{
throw UnexpectedEndOfInput();
auto [line, col] = this->currentLoc();
throw UnexpectedEndOfInput(line, col);
}
std::size_t len = 0;
while (this->afterN(len) != '<')
Expand All @@ -125,7 +139,8 @@ namespace myxml
}
if (!this->afterN(len))
{ // if jump out of while loop due to length limit
throw SyntaxError(fmt::format("expected '<' after text"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected '<' after text"), line, col);
}
return std::shared_ptr<Text>(new Text(*this->takeN(len)));
}
Expand All @@ -144,7 +159,8 @@ namespace myxml
}
if (!this->afterN(len + 2))
{
throw SyntaxError(fmt::format("expected \"]]>\" after CDATA"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected \"]]>\" after CDATA"), line, col);
}
auto it = std::string(*this->takeN(len));
this->takeN(2);
Expand Down Expand Up @@ -176,14 +192,16 @@ namespace myxml
{
if (tag.type != ElementTag::ClosingType::Open)
{
throw SyntaxError(fmt::format("unexpected ending '/' found in closing tag"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("unexpected ending '/' found in closing tag"), line, col);
}
tag.type = ElementTag::ClosingType::Closed;
this->take();
}
if (this->take() != '>')
{
throw SyntaxError(fmt::format("expected '>' at the end of the tag"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected '>' at the end of the tag"), line, col);
}
return tag;
}
Expand Down Expand Up @@ -227,7 +245,8 @@ namespace myxml
case ElementTag::ClosingType::Closing:
if (tag->name != elem->GetName())
{
throw SyntaxError(fmt::format("elem name in closing tag is mismatched with the header"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("elem name in closing tag is mismatched with the header"), line, col);
}
if (!header.attris.empty())
{
Expand All @@ -245,7 +264,8 @@ namespace myxml
break;
}
}
throw UnexpectedEndOfInput();
auto [line, col] = this->currentLoc();
throw UnexpectedEndOfInput(line, col);
}

std::shared_ptr<Element> Parser::ParseElement()
Expand All @@ -269,7 +289,8 @@ namespace myxml
}
else // Closing </tag>
{
throw SyntaxError(fmt::format("unexpected closing tag"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("unexpected closing tag"), line, col);
}
}
else
Expand All @@ -293,15 +314,17 @@ namespace myxml
this->skipWhiteSpaces();
if (this->takeN(2) != "?>")
{
throw SyntaxError(fmt::format("expected \"?>\" at end of xml declaration"));
auto [line, col] = this->currentLoc();
throw SyntaxError(fmt::format("expected \"?>\" at end of xml declaration"), line, col);
}
if (auto decl = Declaration::BuildFromAttrs(attrs); decl)
{
return decl;
}
else
{
throw SemanticError(fmt::format("declaration has incorrect attributes"));
auto [line, col] = this->currentLoc();
throw SemanticError(fmt::format("declaration has incorrect attributes"), line, col);
}
}

Expand All @@ -318,7 +341,8 @@ namespace myxml
}
else
{
throw SemanticError(fmt::format("missing root element in xml document"));
auto [line, col] = this->currentLoc();
throw SemanticError(fmt::format("missing root element in xml document"), line, col);
}
return document;
}
Expand Down

0 comments on commit f5d5524

Please sign in to comment.