Skip to content

Commit

Permalink
Merge pull request #30 from Adamska1008/28-feature-add-line-and-colum…
Browse files Browse the repository at this point in the history
…n-info-to-error-message

28 feature add line and column info to error message
  • Loading branch information
Adamska1008 authored Sep 2, 2024
2 parents df15ec2 + f5d5524 commit 93c2370
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 36 deletions.
11 changes: 10 additions & 1 deletion include/myxml/buffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ namespace myxml
{
private:
std::size_t offset = 0;
std::size_t line = 0;
std::size_t column = 0;

// { pointer to data, data length }
// @returns {pointer to data, data length}
virtual std::tuple<const char *, std::size_t> base() const = 0;
// update line and column
void updateLocation(char);
// update line and column
void updateLocation(std::string_view);

public:
virtual ~Buffer() = default;
Expand All @@ -27,6 +33,8 @@ namespace myxml
std::optional<std::string_view> AfterNM(int, int) const;
std::optional<char> Take();
std::optional<std::string_view> TakeN(int);
// @returns {line, column}
std::tuple<std::size_t, std::size_t> CurrentLocation();
};

class StringBuffer : public Buffer
Expand All @@ -41,5 +49,6 @@ namespace myxml
public:
StringBuffer(std::string_view);
StringBuffer(std::string &&);
StringBuffer(const char *);
};
}
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
40 changes: 37 additions & 3 deletions src/buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,27 @@

namespace myxml
{
void Buffer::updateLocation(char ch)
{
if (ch == '\n')
{
this->column = 0;
this->line++;
}
else
{
this->column++;
}
}

void Buffer::updateLocation(std::string_view strv)
{
for (auto ch : strv)
{
this->updateLocation(ch);
}
}

std::optional<char> Buffer::Peek() const
{
auto [ptr, len] = this->base();
Expand Down Expand Up @@ -49,7 +70,9 @@ namespace myxml
{
return std::nullopt;
}
return ptr[this->offset++];
auto ch = ptr[this->offset++];
this->updateLocation(ch);
return ch;
}

std::optional<std::string_view> Buffer::TakeN(int n)
Expand All @@ -59,9 +82,15 @@ namespace myxml
{
return std::nullopt;
}
std::string_view it(ptr + this->offset, n);
std::string_view strv(ptr + this->offset, n);
this->updateLocation(strv);
offset += n;
return it;
return strv;
}

std::tuple<std::size_t, std::size_t> Buffer::CurrentLocation()
{
return {this->line, this->column};
}

StringBuffer::StringBuffer(std::string_view inner)
Expand All @@ -74,6 +103,11 @@ namespace myxml
{
}

StringBuffer::StringBuffer(const char *ptr)
: StringBuffer(std::string_view(ptr))
{
}

std::tuple<const char *, std::size_t> StringBuffer::base() const
{
auto view = this->getView();
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
Loading

0 comments on commit 93c2370

Please sign in to comment.