Include the filename in the error messages
This commit is contained in:
parent
e04a816024
commit
3c19bf1504
4
TODO
4
TODO
@ -7,14 +7,13 @@
|
|||||||
- Move constants to the symbol table, so we can check at parse time for duplicates.
|
- Move constants to the symbol table, so we can check at parse time for duplicates.
|
||||||
- Don't pass raw pointers to the visitor methods.
|
- Don't pass raw pointers to the visitor methods.
|
||||||
- While loop.
|
- While loop.
|
||||||
- Comparision operators.
|
- Type checking.
|
||||||
- Procedures.
|
- Procedures.
|
||||||
- Calculate additional stack space needed for subexpressions in the allocator
|
- Calculate additional stack space needed for subexpressions in the allocator
|
||||||
visitor and not in the backend.
|
visitor and not in the backend.
|
||||||
- Support immediates greater than 12 bits.
|
- Support immediates greater than 12 bits.
|
||||||
- It seems instructions are correctly encoded only if the compiler is running
|
- It seems instructions are correctly encoded only if the compiler is running
|
||||||
on a little endian architecture.
|
on a little endian architecture.
|
||||||
- Print filename in the error message.
|
|
||||||
- Merge declaration and definition nodes.
|
- Merge declaration and definition nodes.
|
||||||
|
|
||||||
# Shell
|
# Shell
|
||||||
@ -33,4 +32,3 @@
|
|||||||
## Appearance
|
## Appearance
|
||||||
|
|
||||||
- Add a bar with additional information under the prompt (edit_bar), like the hostname.
|
- Add a bar with additional information under the prompt (edit_bar), like the hostname.
|
||||||
- Show current time in the prompt.
|
|
||||||
|
67
cli/cl.cpp
67
cli/cl.cpp
@ -3,55 +3,70 @@
|
|||||||
#include "elna/source/semantic.hpp"
|
#include "elna/source/semantic.hpp"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
namespace elna::cli
|
namespace elna::cli
|
||||||
{
|
{
|
||||||
char *readSource(const char *source)
|
std::string read_source(const char *source)
|
||||||
{
|
{
|
||||||
const std::size_t bufferSize = 255;
|
constexpr std::size_t buffer_size = 4096;
|
||||||
|
|
||||||
std::ifstream input_stream{ source };
|
std::ifstream input_stream{ source, std::ios::binary | std::ios::in };
|
||||||
std::stringstream buffer;
|
std::string output;
|
||||||
buffer << input_stream.rdbuf();
|
if (input_stream.fail())
|
||||||
input_stream.close();
|
{
|
||||||
std::string contents = buffer.str();
|
throw std::ios_base::failure("File does not exist");
|
||||||
char *result = reinterpret_cast<char *>(malloc(contents.size() + 1));
|
}
|
||||||
std::copy(std::cbegin(contents), std::cend(contents), result);
|
while (true)
|
||||||
result[contents.size()] = '\0';
|
{
|
||||||
|
const std::size_t old_size = output.size();
|
||||||
|
output.resize(old_size + buffer_size);
|
||||||
|
input_stream.read(&output[old_size], buffer_size);
|
||||||
|
|
||||||
return result;
|
if (input_stream.eof())
|
||||||
|
{
|
||||||
|
output.resize(old_size + input_stream.gcount());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (input_stream.fail())
|
||||||
|
{
|
||||||
|
throw std::ios_base::failure("Unable to complete reading the source file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_error(const std::unique_ptr<source::error>& compile_error)
|
||||||
|
{
|
||||||
|
std::cerr << compile_error->path().string() << ":"
|
||||||
|
<< compile_error->line() << ':' << compile_error->column()
|
||||||
|
<< ": " << compile_error->what() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file)
|
int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file)
|
||||||
{
|
{
|
||||||
auto sourceText = readSource(in_file.c_str());
|
std::string source_text;
|
||||||
if (sourceText == nullptr)
|
try
|
||||||
|
{
|
||||||
|
source_text = read_source(in_file.c_str());
|
||||||
|
}
|
||||||
|
catch (std::ios_base::failure&)
|
||||||
{
|
{
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
size_t tokensCount{ 0 };
|
size_t tokensCount{ 0 };
|
||||||
auto lex_result = source::lex(sourceText);
|
auto lex_result = source::lex(source_text, in_file);
|
||||||
free(sourceText);
|
|
||||||
if (lex_result.has_errors())
|
if (lex_result.has_errors())
|
||||||
{
|
{
|
||||||
for (const auto& compile_error : lex_result.errors())
|
print_errors(lex_result.errors().cbegin(), lex_result.errors().cend());
|
||||||
{
|
|
||||||
std::cerr << compile_error->line() << ':' << compile_error->column()
|
|
||||||
<< ": " << compile_error->what() << std::endl;
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
source::parser parser{ std::move(lex_result.success()) };
|
source::parser parser{ std::move(lex_result.success()) };
|
||||||
auto ast = parser.parse();
|
auto ast = parser.parse();
|
||||||
if (ast == nullptr)
|
if (ast == nullptr)
|
||||||
{
|
{
|
||||||
for (const auto& compile_error : parser.errors())
|
print_errors(parser.errors().cbegin(), parser.errors().cend());
|
||||||
{
|
|
||||||
std::cerr << compile_error->line() << ':' << compile_error->column()
|
|
||||||
<< ": " << compile_error->what() << std::endl;
|
|
||||||
}
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
auto global_scope = std::make_shared<source::symbol_table>();
|
auto global_scope = std::make_shared<source::symbol_table>();
|
||||||
|
@ -1,9 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include "elna/source/result.hpp"
|
||||||
|
|
||||||
namespace elna::cli
|
namespace elna::cli
|
||||||
{
|
{
|
||||||
char *readSource(const char *source);
|
/**
|
||||||
|
* Reads an input file and returns its contents.
|
||||||
|
*
|
||||||
|
* \param source Input file.
|
||||||
|
*
|
||||||
|
* \return File contents.
|
||||||
|
*/
|
||||||
|
std::string read_source(const char *source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats and prints the given error.
|
||||||
|
*
|
||||||
|
* \param compile_error The error to print.
|
||||||
|
*/
|
||||||
|
void print_error(const std::unique_ptr<source::error>& compile_error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the given errors to the standard output.
|
||||||
|
*
|
||||||
|
* \param begin Pointer to the first error.
|
||||||
|
* \param end Pointer pass the last error.
|
||||||
|
*/
|
||||||
|
template<typename I>
|
||||||
|
void print_errors(I begin, I end)
|
||||||
|
{
|
||||||
|
std::for_each(begin, end, &print_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles \a in_file and writes the generated code into \a out_file.
|
||||||
|
*
|
||||||
|
* \param in_file Input file.
|
||||||
|
* \param out_file Output file.
|
||||||
|
*
|
||||||
|
* \return Exit status.
|
||||||
|
*/
|
||||||
int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file);
|
int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -123,7 +124,13 @@ namespace elna::source
|
|||||||
std::string character;
|
std::string character;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unexpected_character(const std::string& character, const source::position position);
|
/**
|
||||||
|
* \param character Unexpected character.
|
||||||
|
* \param path Source file name.
|
||||||
|
* \param position Unexpected token position.
|
||||||
|
*/
|
||||||
|
unexpected_character(const std::string& character, const std::filesystem::path& path,
|
||||||
|
const source::position position);
|
||||||
|
|
||||||
std::string what() const override;
|
std::string what() const override;
|
||||||
};
|
};
|
||||||
@ -133,14 +140,18 @@ namespace elna::source
|
|||||||
token m_token;
|
token m_token;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit unexpected_token(const token& token);
|
/**
|
||||||
|
* \param token Unexpected token.
|
||||||
|
* \param path Source file name.
|
||||||
|
*/
|
||||||
|
unexpected_token(const token& token, const std::filesystem::path& path);
|
||||||
|
|
||||||
std::string what() const override;
|
std::string what() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lexer
|
struct lexer
|
||||||
{
|
{
|
||||||
lexer(std::vector<token>&& tokens, const position last_position);
|
lexer(std::vector<token>&& tokens, const position last_position, const std::filesystem::path& path);
|
||||||
lexer(const lexer&) = delete;
|
lexer(const lexer&) = delete;
|
||||||
lexer(lexer&&) = default;
|
lexer(lexer&&) = default;
|
||||||
|
|
||||||
@ -217,6 +228,7 @@ namespace elna::source
|
|||||||
std::vector<token> tokens;
|
std::vector<token> tokens;
|
||||||
std::vector<token>::const_iterator iterator;
|
std::vector<token>::const_iterator iterator;
|
||||||
std::list<std::unique_ptr<error>> m_errors;
|
std::list<std::unique_ptr<error>> m_errors;
|
||||||
|
std::filesystem::path source_file;
|
||||||
token eof;
|
token eof;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -224,7 +236,8 @@ namespace elna::source
|
|||||||
* Splits the source text into tokens.
|
* Splits the source text into tokens.
|
||||||
*
|
*
|
||||||
* \param buffer Source text.
|
* \param buffer Source text.
|
||||||
|
* \param path Source file location.
|
||||||
* \return Tokens or error.
|
* \return Tokens or error.
|
||||||
*/
|
*/
|
||||||
elna::source::result<lexer> lex(const std::string& buffer);
|
elna::source::result<lexer> lex(const std::string& buffer, const std::filesystem::path& path);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <filesystem>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -30,12 +31,16 @@ namespace elna::source
|
|||||||
class error
|
class error
|
||||||
{
|
{
|
||||||
position m_position;
|
position m_position;
|
||||||
|
std::filesystem::path m_path;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
* Constructs an error.
|
||||||
|
*
|
||||||
|
* \param path Source file name.
|
||||||
* \param position Error position in the source text.
|
* \param position Error position in the source text.
|
||||||
*/
|
*/
|
||||||
error(const position position);
|
error(const std::filesystem::path& path, const position position);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Error text.
|
/// Error text.
|
||||||
@ -46,6 +51,9 @@ namespace elna::source
|
|||||||
|
|
||||||
/// Error column in the source text.
|
/// Error column in the source text.
|
||||||
std::size_t column() const noexcept;
|
std::size_t column() const noexcept;
|
||||||
|
|
||||||
|
/// Source file name.
|
||||||
|
const std::filesystem::path& path() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -106,7 +114,14 @@ namespace elna::source
|
|||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
name_collision(const std::string& name, const position current, const position previous);
|
/**
|
||||||
|
* \param name Symbol name.
|
||||||
|
* \param path Source file name.
|
||||||
|
* \param current Current symbol position.
|
||||||
|
* \param previous Position of the previously defined symbol.
|
||||||
|
*/
|
||||||
|
name_collision(const std::string& name, const std::filesystem::path& path,
|
||||||
|
const position current, const position previous);
|
||||||
|
|
||||||
std::string what() const override;
|
std::string what() const override;
|
||||||
};
|
};
|
||||||
|
@ -267,8 +267,9 @@ namespace elna::source
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
unexpected_character::unexpected_character(const std::string& character, const source::position position)
|
unexpected_character::unexpected_character(const std::string& character, const std::filesystem::path& path,
|
||||||
: error(position), character(character)
|
const source::position position)
|
||||||
|
: error(path, position), character(character)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,8 +282,8 @@ namespace elna::source
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
unexpected_token::unexpected_token(const token& token)
|
unexpected_token::unexpected_token(const token& token, const std::filesystem::path& path)
|
||||||
: error(token.position()), m_token(token)
|
: error(path, token.position()), m_token(token)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,8 +292,9 @@ namespace elna::source
|
|||||||
return "Unexpected token " + m_token.to_string();
|
return "Unexpected token " + m_token.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
lexer::lexer(std::vector<token>&& tokens, const position last_position)
|
lexer::lexer(std::vector<token>&& tokens, const position last_position, const std::filesystem::path& path)
|
||||||
: tokens(std::move(tokens)), iterator(this->tokens.cbegin()), eof(token(token::type::eof, last_position))
|
: tokens(std::move(tokens)), iterator(this->tokens.cbegin()), eof(token(token::type::eof, last_position)),
|
||||||
|
source_file(path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +330,7 @@ namespace elna::source
|
|||||||
|
|
||||||
void lexer::add_error(const token& expected)
|
void lexer::add_error(const token& expected)
|
||||||
{
|
{
|
||||||
m_errors.push_back(std::make_unique<unexpected_token>(expected));
|
m_errors.push_back(std::make_unique<unexpected_token>(expected, this->source_file));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::reference_wrapper<const token>> lexer::advance(const token::type token_type)
|
std::optional<std::reference_wrapper<const token>> lexer::advance(const token::type token_type)
|
||||||
@ -367,7 +369,7 @@ namespace elna::source
|
|||||||
return m_errors;
|
return m_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
result<lexer> lex(const std::string& buffer)
|
result<lexer> lex(const std::string& buffer, const std::filesystem::path& path)
|
||||||
{
|
{
|
||||||
std::vector<token> tokens;
|
std::vector<token> tokens;
|
||||||
auto [iterator, text_end] = text_iterators(buffer);
|
auto [iterator, text_end] = text_iterators(buffer);
|
||||||
@ -492,10 +494,10 @@ namespace elna::source
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return result<lexer>(unexpected_character{ std::string{ *iterator }, iterator.position() });
|
return result<lexer>(unexpected_character{ std::string{ *iterator }, path, iterator.position() });
|
||||||
}
|
}
|
||||||
++iterator;
|
++iterator;
|
||||||
}
|
}
|
||||||
return result<lexer>(std::in_place, std::move(tokens), iterator.position());
|
return result<lexer>(std::in_place, std::move(tokens), iterator.position(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
namespace elna::source
|
namespace elna::source
|
||||||
{
|
{
|
||||||
error::error(const position position)
|
error::error(const std::filesystem::path& path, const position position)
|
||||||
: m_position(position)
|
: m_position(position), m_path(path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +17,14 @@ namespace elna::source
|
|||||||
return this->m_position.column;
|
return this->m_position.column;
|
||||||
}
|
}
|
||||||
|
|
||||||
name_collision::name_collision(const std::string& name, const position current, const position previous)
|
const std::filesystem::path& error::path() const noexcept
|
||||||
: error(current), name(name), previous(previous)
|
{
|
||||||
|
return this->m_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
name_collision::name_collision(const std::string& name, const std::filesystem::path& path,
|
||||||
|
const position current, const position previous)
|
||||||
|
: error(path, current), name(name), previous(previous)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1 @@
|
|||||||
1:1: Unexpected token «identifier»
|
tests/single_word_error.eln:1:1: Unexpected token «identifier»
|
||||||
|
Loading…
Reference in New Issue
Block a user