Compare commits

...

8 Commits

Author SHA1 Message Date
a0945e54b2 Update tests
Apparently now error reporting works better!! I wonder why...
2022-11-01 22:29:21 +01:00
9713e9b239 AST: Reorder constructors 2022-11-01 22:29:00 +01:00
70f564fe58 Error: Add reminder FIXME 2022-11-01 22:28:44 +01:00
f8d76c9bea Result: Reorder constructors 2022-11-01 22:28:34 +01:00
2cb477447e Lexer, Parser: Reorder constructors and use ssize_t for signed indices 2022-11-01 22:28:21 +01:00
06f24e770b Location: Add copy and move constructors and fix operator= 2022-11-01 22:27:45 +01:00
6b505c82e7 Token: Add a copy constructor and fix operator= 2022-11-01 22:27:18 +01:00
fb990ac4a8 Build with -Wall, -Wextra, -Werror and -pedantic
Helps a lot, I've discovered in the past months.
2022-11-01 22:26:49 +01:00
26 changed files with 101 additions and 48 deletions

View File

@ -73,6 +73,12 @@ target_include_directories(sapphirec PUBLIC src)
target_include_directories(sapphirec PUBLIC src/external/tclap-1.2.5/include)
target_include_directories(sapphirec PUBLIC src/external)
target_precompile_headers(sapphirec PUBLIC src/sapphirepch.h)
set_property(TARGET sapphirec PROPERTY COMPILE_WARNING_AS_ERROR ON)
target_compile_options(sapphirec PRIVATE
$<$<CXX_COMPILER_ID:MSVC>:/W4>
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Wpedantic>
)
llvm_map_components_to_libnames(llvm_libs all core support irreader x86asmparser x86codegen x86desc x86disassembler x86info x86targetmca aarch64asmparser aarch64codegen aarch64desc aarch64disassembler aarch64info aarch64utils)

View File

@ -1,7 +1,7 @@
#include "BinaryOpNode.h"
BinaryOpNode::BinaryOpNode(std::shared_ptr<ExprNode> left, std::shared_ptr<ExprNode> right)
: left(left), right(right), ExprNode()
: ExprNode(), left(left), right(right)
{
}

View File

@ -6,7 +6,7 @@ EmptyFunctionNode::EmptyFunctionNode(FunctionPrototype prototype) : TopLevelNode
{
}
void EmptyFunctionNode::codegen(IRBuilder* generator, llvm::Module* module)
void EmptyFunctionNode::codegen([[maybe_unused]] IRBuilder* generator, llvm::Module* module)
{
llvm::Function* Function = module->getFunction(prototype.name);
if (!Function)

View File

@ -1,6 +1,6 @@
#include "ExprNode.h"
ExprNode::ExprNode(std::shared_ptr<ExprNode> child) : child(child), ASTNode()
ExprNode::ExprNode(std::shared_ptr<ExprNode> child) : ASTNode(), child(child)
{
}

View File

@ -1,6 +1,6 @@
#include "StatementNode.h"
StatementNode::StatementNode(std::shared_ptr<ExprNode> child) : child(child), ASTNode()
StatementNode::StatementNode(std::shared_ptr<ExprNode> child) : ASTNode(), child(child)
{
}

View File

@ -5,7 +5,10 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/InlineAsm.h"
Syscall0Node::Syscall0Node(int syscall_number) : sys_num(syscall_number), ExprNode()
// FIXME: This API is HIGHLY Linux-specific. The right thing to be done should be to expose an inline assembly expression, to do this kind of stuff freely
// depending on the platform in core and any project that wants to use inline assembly, such as an OS kernel or embedded program :^)
Syscall0Node::Syscall0Node(int syscall_number) : ExprNode(), sys_num(syscall_number)
{
}
@ -14,7 +17,7 @@ Syscall0Node::~Syscall0Node()
}
Syscall1Node::Syscall1Node(int syscall_number, std::shared_ptr<ASTNode> arg1)
: sys_num(syscall_number), arg1(arg1), ExprNode()
: ExprNode(), sys_num(syscall_number), arg1(arg1)
{
}
@ -23,7 +26,7 @@ Syscall1Node::~Syscall1Node()
}
Syscall2Node::Syscall2Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), ExprNode()
: ExprNode(), sys_num(syscall_number), arg1(arg1), arg2(arg2)
{
}
@ -33,7 +36,7 @@ Syscall2Node::~Syscall2Node()
Syscall3Node::Syscall3Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), ExprNode()
: ExprNode(), sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3)
{
}
@ -43,7 +46,7 @@ Syscall3Node::~Syscall3Node()
Syscall4Node::Syscall4Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), ExprNode()
: ExprNode(), sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4)
{
}
@ -53,7 +56,7 @@ Syscall4Node::~Syscall4Node()
Syscall5Node::Syscall5Node(int syscall_number, std::shared_ptr<ASTNode> arg1, std::shared_ptr<ASTNode> arg2,
std::shared_ptr<ASTNode> arg3, std::shared_ptr<ASTNode> arg4, std::shared_ptr<ASTNode> arg5)
: sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5), ExprNode()
: ExprNode(), sys_num(syscall_number), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5)
{
}

View File

@ -1,6 +1,6 @@
#include "UnaryOpNode.h"
UnaryOpNode::UnaryOpNode(std::shared_ptr<ExprNode> operand) : operand(operand), ExprNode()
UnaryOpNode::UnaryOpNode(std::shared_ptr<ExprNode> operand) : ExprNode(), operand(operand)
{
}

View File

@ -37,6 +37,8 @@ void Error::show_import_lines(const Location& loc, void (*import_line_printer)(c
}
}
// FIXME: Seems like the cursor that indicates where the error is is a bit offset to the right.
[[noreturn]] void Error::throw_error(const Location& loc, const std::string line_text, const std::string& details)
{
show_import_lines(loc, show_import_line, std::cerr);

View File

@ -7,7 +7,7 @@
#define IDENTIFIERS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ_0123456789"
#define DIGITS "0123456789"
Lexer::Lexer(const std::string& fname) : location(1, 0, fname), index(-1), previous_location(1, 0, fname)
Lexer::Lexer(const std::string& fname) : location(1, 0, fname), previous_location(1, 0, fname), index(-1)
{
}
@ -17,10 +17,10 @@ Lexer::~Lexer()
int Lexer::advance()
{
previous_location = location;
previous_location = Location{ location };
++index;
location.advance();
if (index >= current_lexed_text.size()) return 0;
if (index >= (ssize_t)current_lexed_text.size()) return 0;
current_char = current_lexed_text[index];
location.pos_from_char(current_char);
if (current_char == '\n')
@ -46,10 +46,10 @@ int Lexer::rewind()
std::string Lexer::recalculate_current_line(const std::string& text)
{
int idx = index;
ssize_t idx = index;
std::string final_str;
++idx;
while (idx != text.size() && text[idx] != '\n')
while (idx != (ssize_t)text.size() && text[idx] != '\n')
{
final_str += text[idx];
++idx;
@ -106,7 +106,7 @@ TokenStream Lexer::lex(const std::string& text)
switch (current_char)
{
case '/':
if (index + 1 != current_lexed_text.size())
if (index + 1 != (ssize_t)current_lexed_text.size())
{
if (current_lexed_text[index + 1] == '/')
{
@ -172,7 +172,7 @@ TokenStream Lexer::lex(const std::string& text)
break;
case '\377':
result.push_back(Token(TT_EOF, location));
return std::move(result);
return result;
default:
Error::throw_error(location, current_line_text, "unknown character");
}
@ -180,7 +180,7 @@ TokenStream Lexer::lex(const std::string& text)
result.push_back(Token(TT_EOF, location));
return std::move(result);
return result;
}
Token Lexer::create_identifier()
@ -303,7 +303,7 @@ Token Lexer::create_string()
}
if (current_char == '\\')
{
if (index + 1 == current_lexed_text.size())
if (index + 1 == (ssize_t)current_lexed_text.size())
{
Error::throw_error(location, current_line_text, "unfinished escape sequence");
}

View File

@ -19,7 +19,7 @@ class Lexer
int advance();
int rewind();
char current_char;
int index;
ssize_t index;
Lexer(const std::string& filename);

View File

@ -30,18 +30,19 @@ void Location::pos_from_char(const char& character)
}
}
void Location::operator=(const Location& other)
Location::Location(const Location& other)
: line(other.line), column(other.column), filename(other.filename), parent(other.parent)
{
}
Location::Location(Location&& other)
: line(other.line), column(other.column), filename(std::move(other.filename)), parent(std::move(other.parent))
{
Location copied = copy(other);
line = copied.line;
column = copied.column;
parent = copied.parent;
filename = std::move(copied.filename);
}
Location Location::copy(const Location& other)
{
Location result(other.line, other.column, other.filename);
result.parent = other.parent;
return std::move(result);
return result;
}

View File

@ -14,6 +14,14 @@ struct Location
/* Creates a Location with the given parameters. */
Location(int line, int column, std::string filename);
Location(Location&& other);
Location(const Location& other);
Location operator=(const Location& other)
{
return Location(other);
}
~Location();
/* Returns a string of the format FILE:LINE:COL. */
@ -25,8 +33,6 @@ struct Location
/* Advance to the next line if provided a newline. */
void pos_from_char(const char& character);
void operator=(const Location& other);
/* Returns a copy of the original Location. */
static Location copy(const Location& other);
};

View File

@ -37,7 +37,7 @@ std::shared_ptr<ProgramNode> Parser::parse()
int Parser::advance()
{
++index;
if (index < tokens.size())
if (index < (ssize_t)tokens.size())
{
current_token = &tokens[index];
}
@ -136,7 +136,7 @@ Result<TopLevelNode> Parser::function()
{
proto.returnType = m_type_map.at(current_token->string_value.value());
}
catch (std::out_of_range)
catch (const std::out_of_range&)
{
return Err<TopLevelNode>("Expected type name", current_token);
}

View File

@ -14,7 +14,7 @@ class Parser
private:
Parser(const TokenStream& tokens);
TokenStream tokens;
int index = -1;
ssize_t index = -1;
int advance();
Token* current_token;

View File

@ -35,10 +35,10 @@ template<typename T> class Result
bool m_is_error;
std::string m_error;
Result(T* result, Token* token) : m_result(result), m_token(token), m_is_error(false)
Result(T* result, Token* token) : m_token(token), m_result(result), m_is_error(false)
{
}
Result(std::string&& error, Token* token) : m_error(error), m_token(token), m_is_error(true)
Result(std::string&& error, Token* token) : m_token(token), m_is_error(true), m_error(error)
{
}
};

View File

@ -1,6 +1,22 @@
#include "Token.h"
#include "utils.h"
Token::Token(const Token& other) : type(other.type), location(other.location), m_line_text(other.m_line_text)
{
if (other.int_value.has_value())
{
int_value = other.int_value.value();
}
else if (other.float_value.has_value())
{
float_value = other.float_value.value();
}
else if (other.string_value.has_value())
{
string_value = other.string_value.value();
}
}
Token::Token(TokenType type) : type(type), location(0, 0, "")
{
}
@ -9,7 +25,7 @@ Token::Token(TokenType type, const Location& location) : type(type), location(lo
{
}
Token::Token(TokenType type, std::string value) : type(type), location(0, 0, ""), string_value(std::move(value))
Token::Token(TokenType type, std::string value) : type(type), string_value(std::move(value)), location(0, 0, "")
{
}
@ -45,17 +61,34 @@ Token Token::copy_with_new_type(const TokenType& type) const
result.string_value = string_value.value();
}
return std::move(result);
return result;
}
Token Token::make_with_line(const Token& origin, const std::string& line_text)
{
Token result = origin.copy_with_new_type(origin.type);
return std::move(result);
result.m_line_text = line_text;
return result;
}
void Token::operator=(const Token& other)
{
*this = other.copy_with_new_type(other.type);
type = other.type;
location = other.location;
m_line_text = other.m_line_text;
if (other.int_value.has_value())
{
int_value = other.int_value.value();
}
else if (other.float_value.has_value())
{
float_value = other.float_value.value();
}
else if (other.string_value.has_value())
{
string_value = other.string_value.value();
}
}

View File

@ -56,6 +56,8 @@ struct Token
Location location;
Token(const Token& other);
Token(TokenType type);
Token(TokenType type, const Location& location);

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/body-invalid-expr.sp:2:7: \u001b[31;49merror: \u001b[0;0mInvalid syntax\n2 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/body-invalid-expr.sp:2:8: \u001b[31;49merror: \u001b[0;0mInvalid syntax\n2 0 5 +\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/body-not-math-expr.sp:2:5: \u001b[31;49merror: \u001b[0;0mexpected a number\n2 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/body-not-math-expr.sp:2:5: \u001b[31;49merror: \u001b[0;0mexpected a number\n2 syscall1(60, 1); // sys_exit(1)\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/empty-let.sp:1:4: \u001b[31;49merror: \u001b[0;0mExpected @\n1 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/empty-let.sp:1:5: \u001b[31;49merror: \u001b[0;0mExpected @\n1 let;\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/function-no-in.sp:1:17: \u001b[31;49merror: \u001b[0;0mExpected 'in' or semicolon\n1 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/function-no-in.sp:1:20: \u001b[31;49merror: \u001b[0;0mExpected 'in' or semicolon\n1 let @main : i32 {\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/invalid-type.sp:1:13: \u001b[31;49merror: \u001b[0;0mExpected type name\n1 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/invalid-type.sp:1:15: \u001b[31;49merror: \u001b[0;0mExpected type name\n1 let @main : u56 in {\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "\u001b[1;1mtests/lex-multiple-periods.sp:2:9: \u001b[33;49mwarning: \u001b[0;0mfloats can only have one dot\n2 3.45.6\n \u001b[33;49m^\u001b[0;0m\n",
"stderr": "\u001b[1;1mtests/lex-multiple-periods.sp:2:9: \u001b[31;49merror: \u001b[0;0mInvalid syntax\n2 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/lex-multiple-periods.sp:2:10: \u001b[31;49merror: \u001b[0;0mInvalid syntax\n2 3.45.6\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/lex-unfinished-string.sp:2:19: \u001b[31;49merror: \u001b[0;0mexpected end of string but got newline\n2 'This is a test\n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/lex-unfinished-string.sp:3:0: \u001b[31;49merror: \u001b[0;0mexpected end of string but got newline\n3 'This is a test\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/top-level-math.sp:1:1: \u001b[31;49merror: \u001b[0;0mExpected let\n1 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/top-level-math.sp:1:1: \u001b[31;49merror: \u001b[0;0mExpected let\n1 4 + 5 - 6\n \u001b[31;49m^\u001b[0;0m\n"
}
}

View File

@ -4,6 +4,6 @@
"flags": [],
"exit-code": 1,
"stdout": "",
"stderr": "\u001b[1;1mtests/unended-function.sp:1:11: \u001b[31;49merror: \u001b[0;0mExpected 'in', colon or semicolon\n1 \n \u001b[31;49m^\u001b[0;0m\n"
"stderr": "\u001b[1;1mtests/unended-function.sp:1:12: \u001b[31;49merror: \u001b[0;0mExpected 'in', colon or semicolon\n1 \n \u001b[31;49m^\u001b[0;0m\n"
}
}