Hnalding parsing errors
This commit is contained in:
parent
8835751449
commit
53b626fd2f
68
.vscode/settings.json
vendored
68
.vscode/settings.json
vendored
@ -1,6 +1,72 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.tcc": "cpp",
|
||||
"istream": "cpp"
|
||||
"istream": "cpp",
|
||||
"any": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"condition_variable": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"map": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"numbers": "cpp",
|
||||
"ostream": "cpp",
|
||||
"semaphore": "cpp",
|
||||
"shared_mutex": "cpp",
|
||||
"span": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"stop_token": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"text_encoding": "cpp",
|
||||
"thread": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"variant": "cpp"
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,11 @@ ADD_LIBRARY(hoocore STATIC
|
||||
Visitor.cpp
|
||||
Compiler.cpp
|
||||
Compiler.hpp
|
||||
Node.hpp)
|
||||
Node.hpp
|
||||
ParseError.hpp
|
||||
ParseErrorHandler.hpp
|
||||
ParseErrorHandler.cpp
|
||||
ParseErrorException.hpp)
|
||||
ADD_EXECUTABLE(hoo
|
||||
Hoo.cpp Visitor.cpp
|
||||
${ANTLR_GENERATED_DIR}/HooBaseVisitor.cpp
|
||||
|
||||
@ -1,12 +1,18 @@
|
||||
#include "Compiler.hpp"
|
||||
#include "ParseErrorException.hpp"
|
||||
#include "ParseError.hpp"
|
||||
|
||||
Compiler::Compiler(const std::string &input, const std::string &moduleName) : _input(input), _moduleName(moduleName)
|
||||
#include <iostream>
|
||||
|
||||
Compiler::Compiler(const std::string &input,
|
||||
const std::string &moduleName) : _input(input), _moduleName(moduleName)
|
||||
{
|
||||
_input_stream = new antlr4::ANTLRInputStream(_input);
|
||||
_lexer = new HooLexer(_input_stream);
|
||||
_tokens = new antlr4::CommonTokenStream(_lexer);
|
||||
_parser = new HooParser(_tokens);
|
||||
_visitor = new Visitor(_moduleName);
|
||||
_parser->setErrorHandler(std::make_shared<ParseErrorHandler>());
|
||||
}
|
||||
|
||||
Compiler::~Compiler()
|
||||
@ -22,14 +28,30 @@ std::any Compiler::compile()
|
||||
{
|
||||
try
|
||||
{
|
||||
auto error_handler = std::dynamic_pointer_cast<ParseErrorHandler>(_parser->getErrorHandler());
|
||||
antlr4::tree::ParseTree *tree = parse();
|
||||
if (tree == nullptr)
|
||||
{
|
||||
std::cout << "Parse failed" << std::endl;
|
||||
std::cerr << "Parse failed" << std::endl;
|
||||
}
|
||||
auto result = _visitor->visit(tree);
|
||||
auto parseErrors = error_handler->getErrors();
|
||||
if (parseErrors.size() > 0)
|
||||
{
|
||||
throw ParseCollectiveErrorException(parseErrors);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (const ParseCollectiveErrorException &e)
|
||||
{
|
||||
std::cerr << e.getMessage() << std::endl;
|
||||
throw;
|
||||
}
|
||||
catch (const ParseErrorException &e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Compilation Error: " << e.what() << std::endl;
|
||||
|
||||
@ -4,8 +4,10 @@
|
||||
#include "HooLexer.h"
|
||||
#include "HooParser.h"
|
||||
#include "Visitor.hpp"
|
||||
#include "ParseErrorHandler.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class Compiler
|
||||
{
|
||||
|
||||
10
src/Node.hpp
10
src/Node.hpp
@ -26,8 +26,14 @@ private:
|
||||
llvm::Value *_value;
|
||||
|
||||
public:
|
||||
Node(NodeType nodeType, DataType dataType, llvm::Value *value) : _nodeType(nodeType), _dataType(dataType), _value(value) {}
|
||||
Node(const Node &other) : _nodeType(other._nodeType), _dataType(other._dataType), _value(other._value) {}
|
||||
Node(NodeType nodeType, DataType dataType, llvm::Value *value)
|
||||
: _nodeType(nodeType),
|
||||
_dataType(dataType),
|
||||
_value(value) {}
|
||||
Node(const Node &other)
|
||||
: _nodeType(other._nodeType),
|
||||
_dataType(other._dataType),
|
||||
_value(other._value) {}
|
||||
|
||||
NodeType getNodeType() const { return _nodeType; }
|
||||
DataType getDataType() const { return _dataType; }
|
||||
|
||||
21
src/ParseError.hpp
Normal file
21
src/ParseError.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
class ParseError
|
||||
{
|
||||
private:
|
||||
size_t line_no;
|
||||
size_t char_pos;
|
||||
std::string message;
|
||||
|
||||
public:
|
||||
ParseError(size_t line, size_t pos, const std::string &msg)
|
||||
: line_no(line), char_pos(pos), message(msg) {}
|
||||
ParseError(const ParseError &other) : ParseError(other.line_no, other.char_pos, other.message) {}
|
||||
|
||||
size_t getLineNo() const { return line_no; }
|
||||
size_t getCharPos() const { return char_pos; }
|
||||
std::string getMessage() const { return message; }
|
||||
};
|
||||
61
src/ParseErrorException.hpp
Normal file
61
src/ParseErrorException.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include "ParseErrorException.hpp"
|
||||
#include "ParseError.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class ParseErrorException : public std::exception
|
||||
{
|
||||
std::string _message;
|
||||
size_t _line_number;
|
||||
size_t _character_position;
|
||||
std::string _module_name;
|
||||
|
||||
public:
|
||||
ParseErrorException(const std::string &module_name,
|
||||
size_t line_number,
|
||||
size_t character_position,
|
||||
const std::string &message)
|
||||
: _message(message),
|
||||
_line_number(line_number),
|
||||
_character_position(character_position),
|
||||
_module_name(module_name)
|
||||
{
|
||||
}
|
||||
|
||||
size_t getLineNumber() const { return _line_number; }
|
||||
size_t getCharacterPosition() const { return _character_position; }
|
||||
std::string getModuleName() const { return _module_name; }
|
||||
|
||||
ParseErrorException(const ParseErrorException &other) : std::exception(other),
|
||||
_module_name(other._module_name),
|
||||
_line_number(other._line_number),
|
||||
_character_position(other._character_position) {}
|
||||
|
||||
const char *what() const noexcept override { return _message.c_str(); }
|
||||
};
|
||||
|
||||
class ParseCollectiveErrorException : public std::exception
|
||||
{
|
||||
std::vector<ParseError> _errors;
|
||||
|
||||
public:
|
||||
ParseCollectiveErrorException(const std::vector<ParseError> &errors)
|
||||
: _errors(errors)
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<ParseError> &getErrors() const { return _errors; }
|
||||
std::string getMessage() const
|
||||
{
|
||||
std::string result;
|
||||
for (const auto &error : _errors)
|
||||
{
|
||||
result += error.getMessage() + "\n";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
39
src/ParseErrorHandler.cpp
Normal file
39
src/ParseErrorHandler.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ParseErrorHandler.hpp"
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
void ParseErrorHandler::reportError(antlr4::Parser *recognizer, const antlr4::RecognitionException &e)
|
||||
{
|
||||
auto offendingToken = e.getOffendingToken();
|
||||
auto line_no = offendingToken->getLine();
|
||||
auto char_pos = offendingToken->getLine();
|
||||
ParseError error(line_no, char_pos, "Parse error");
|
||||
errors.push_back(error);
|
||||
}
|
||||
|
||||
void ParseErrorHandler::recover(antlr4::Parser *recognizer, std::exception_ptr e)
|
||||
{
|
||||
recognizer->consume();
|
||||
}
|
||||
|
||||
antlr4::Token *ParseErrorHandler::recoverInline(antlr4::Parser *recognizer)
|
||||
{
|
||||
auto offendingToken = recognizer->getCurrentToken();
|
||||
auto line_no = offendingToken->getLine();
|
||||
auto char_pos = offendingToken->getLine();
|
||||
ParseError error(line_no, char_pos, "Parse error");
|
||||
errors.push_back(error);
|
||||
recognizer->consume();
|
||||
return recognizer->getCurrentToken();
|
||||
}
|
||||
|
||||
void ParseErrorHandler::sync(antlr4::Parser *recognizer)
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<ParseError> &ParseErrorHandler::getErrors() const
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
24
src/ParseErrorHandler.hpp
Normal file
24
src/ParseErrorHandler.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "ParseError.hpp"
|
||||
|
||||
#include "antlr4-runtime.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
class ParseErrorHandler : public antlr4::DefaultErrorStrategy
|
||||
{
|
||||
private:
|
||||
std::vector<ParseError> errors;
|
||||
|
||||
public:
|
||||
void reportError(antlr4::Parser *recognizer, const antlr4::RecognitionException &e) override;
|
||||
|
||||
void recover(antlr4::Parser *recognizer, std::exception_ptr e) override;
|
||||
|
||||
antlr4::Token *recoverInline(antlr4::Parser *recognizer) override;
|
||||
|
||||
void sync(antlr4::Parser *recognizer) override;
|
||||
|
||||
const std::vector<ParseError> &getErrors() const;
|
||||
};
|
||||
@ -1,5 +1,6 @@
|
||||
#include "Visitor.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "ParseErrorException.hpp"
|
||||
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
@ -72,7 +73,13 @@ std::any Visitor::visitLiteral(HooParser::LiteralContext *ctx)
|
||||
return std::any{Node(NODE_LITERAL, DATATYPE_STRING, stringConstant)};
|
||||
}
|
||||
|
||||
return std::any{Node(NODE_IGNORE, DATATYPE_VOID, nullptr)};
|
||||
auto line_no = ctx->getStart()->getLine();
|
||||
auto char_pos = ctx->getStart()->getCharPositionInLine();
|
||||
auto message = "Invalid literal near line " + std::to_string(line_no) + ", character " + std::to_string(char_pos) + " on " + _moduleName + ".";
|
||||
#ifndef NDDEBUG
|
||||
std::cerr << message << std::endl;
|
||||
#endif
|
||||
throw ParseErrorException(_moduleName, line_no, char_pos, message);
|
||||
}
|
||||
|
||||
std::any Visitor::visitLiteralStatement(HooParser::LiteralStatementContext *ctx)
|
||||
@ -85,6 +92,7 @@ std::any Visitor::visitLiteralStatement(HooParser::LiteralStatementContext *ctx)
|
||||
std::any Visitor::visitStatement(HooParser::StatementContext *ctx)
|
||||
{
|
||||
auto listeral_stmt_ctx = ctx->literalStatement();
|
||||
std::cout << "Statement: " << ctx->getText() << std::endl;
|
||||
if (listeral_stmt_ctx != nullptr)
|
||||
{
|
||||
auto result = visitLiteralStatement(listeral_stmt_ctx);
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
class Visitor : public HooBaseVisitor
|
||||
{
|
||||
private:
|
||||
const std::string &_moduleName;
|
||||
std::string _moduleName;
|
||||
std::shared_ptr<llvm::LLVMContext> _context;
|
||||
std::shared_ptr<llvm::Module> _module;
|
||||
std::shared_ptr<llvm::IRBuilder<>> _builder;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "Compiler.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "ParseErrorException.hpp"
|
||||
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
@ -10,19 +12,17 @@ void testBoolLiteral(const std::string &input, bool expectedValue)
|
||||
auto result = compiler->compile();
|
||||
auto boolNode = std::any_cast<Node>(result);
|
||||
|
||||
// Validate node type and data type
|
||||
ASSERT_EQ(boolNode.getNodeType(), NODE_LITERAL);
|
||||
ASSERT_EQ(boolNode.getDataType(), DATATYPE_BOOL);
|
||||
|
||||
// Validate LLVM value
|
||||
auto value = boolNode.getValue();
|
||||
ASSERT_NE(value, nullptr);
|
||||
|
||||
auto value_constant = llvm::dyn_cast<llvm::ConstantInt>(value);
|
||||
ASSERT_NE(value_constant, nullptr);
|
||||
|
||||
// Check the boolean value (1 for true, 0 for false)
|
||||
ASSERT_EQ(value_constant->getValue().getLimitedValue(), static_cast<uint64_t>(expectedValue));
|
||||
ASSERT_EQ(value_constant->getValue().getLimitedValue(),
|
||||
static_cast<uint64_t>(expectedValue));
|
||||
}
|
||||
|
||||
// Test fixture for boolean tests
|
||||
@ -55,17 +55,17 @@ TEST_F(BoolTest, LiteralFalse)
|
||||
TEST_F(BoolTest, InvalidLiteral)
|
||||
{
|
||||
auto compiler = std::make_unique<Compiler>("notbool;", "main");
|
||||
ASSERT_THROW(compiler->compile(), std::invalid_argument);
|
||||
ASSERT_THROW(compiler->compile(), ParseErrorException);
|
||||
}
|
||||
|
||||
TEST_F(BoolTest, MissingSemicolon)
|
||||
{
|
||||
auto compiler = std::make_unique<Compiler>("true", "main");
|
||||
ASSERT_THROW(compiler->compile(), std::runtime_error);
|
||||
ASSERT_THROW(compiler->compile(), ParseCollectiveErrorException);
|
||||
}
|
||||
|
||||
TEST_F(BoolTest, MixedCaseLiteral)
|
||||
{
|
||||
auto compiler = std::make_unique<Compiler>("True;", "main");
|
||||
ASSERT_THROW(compiler->compile(), std::invalid_argument); // Expect strict case-sensitivity
|
||||
ASSERT_THROW(compiler->compile(), ParseErrorException);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user