Skip to content

Commit

Permalink
Implement more control over decimal numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
quantumsheep committed Aug 10, 2020
1 parent 24ce1e4 commit 40f4306
Show file tree
Hide file tree
Showing 6 changed files with 551 additions and 431 deletions.
14 changes: 14 additions & 0 deletions include/Sand/Exceptions/NumberOutOfRangeException.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include <Sand/Exceptions/CompilationException.hpp>
#include <Sand/Type.hpp>

namespace Sand
{
class NumberOutOfRangeException : public CompilationException
{
public:
NumberOutOfRangeException(const fs::path &source, antlr4::Token *token, const std::string &number) : CompilationException(source, "Number out of range: '" + number + "'.", token) {}
NumberOutOfRangeException(const fs::path &source, antlr4::Token *token, const std::string &number, const std::string &type) : CompilationException(source, "Number out of range for type '" + type + "': '" + number + "'.", token) {}
};
} // namespace Sand
10 changes: 5 additions & 5 deletions include/Sand/Type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,27 +293,27 @@ class Type : public Name
return llvm::Type::getVoidTy(context);
}

static llvm::Type *llvm_i1(llvm::LLVMContext &context)
static llvm::IntegerType *llvm_i1(llvm::LLVMContext &context)
{
return llvm::Type::getInt1Ty(context);
}

static llvm::Type *llvm_i8(llvm::LLVMContext &context)
static llvm::IntegerType *llvm_i8(llvm::LLVMContext &context)
{
return llvm::Type::getInt8Ty(context);
}

static llvm::Type *llvm_i16(llvm::LLVMContext &context)
static llvm::IntegerType *llvm_i16(llvm::LLVMContext &context)
{
return llvm::Type::getInt16Ty(context);
}

static llvm::Type *llvm_i32(llvm::LLVMContext &context)
static llvm::IntegerType *llvm_i32(llvm::LLVMContext &context)
{
return llvm::Type::getInt32Ty(context);
}

static llvm::Type *llvm_i64(llvm::LLVMContext &context)
static llvm::IntegerType *llvm_i64(llvm::LLVMContext &context)
{
return llvm::Type::getInt64Ty(context);
}
Expand Down
19 changes: 15 additions & 4 deletions src/grammar/SandLexer.g4
Original file line number Diff line number Diff line change
Expand Up @@ -126,22 +126,33 @@ CharLiteral: '\'' CharChar+ '\'';
fragment StringChar: ~ ["\r\n] | Escape;
fragment CharChar: ~ ['\r\n] | Escape;
DecimalLiteral: NONZERODIGIT (DIGITSEPARATOR? DIGIT)*;
DecimalLiteral:
NONZERODIGIT (DIGITSEPARATOR? DIGIT)* IntegerType?;
FloatingLiteral:
(DecimalLiteral | ZeroLiteral)? '.' DIGIT (
DIGITSEPARATOR? DIGIT
)*;
ZeroLiteral: '0';
ZeroLiteral: '0' IntegerType?;
HexadecimalLiteral: ('0x' | '0X') HEXADECIMALDIGIT (
DIGITSEPARATOR? HEXADECIMALDIGIT
)*;
)* IntegerType?;
BinaryLiteral: ('0b' | '0B') BINARYDIGIT (
DIGITSEPARATOR? BINARYDIGIT
)*;
)* IntegerType?;
fragment IntegerType:
'i8'
| 'i16'
| 'i32'
| 'i64'
| 'u8'
| 'u16'
| 'u32'
| 'u64';
// Comments
Comment: '//' CommentLine* -> skip;
Expand Down
121 changes: 93 additions & 28 deletions src/grammar/Visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <Sand/Exceptions/NotAClassOrNamespaceException.hpp>
#include <Sand/Exceptions/NotAGenericException.hpp>
#include <Sand/Exceptions/NotAPointerException.hpp>
#include <Sand/Exceptions/NumberOutOfRangeException.hpp>
#include <Sand/Exceptions/OpaqueTypeNotAllowedException.hpp>
#include <Sand/Exceptions/PropertyNotFoundException.hpp>
#include <Sand/Exceptions/ReturnOutsideOfFunctionException.hpp>
Expand All @@ -58,7 +59,9 @@

#include <Sand/filesystem.hpp>

#include <limits>
#include <regex>
#include <tuple>

namespace Sand
{
Expand Down Expand Up @@ -3315,53 +3318,115 @@ class Visitor
{
auto scope = this->scopes.top();

const auto remove_digit_separators = [](std::string &str) {
const auto parse_integer = [&](std::string str, int base = 10) -> Values::Constant * {
str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
str.erase(std::remove(str.begin(), str.end(), '\''), str.end());
};

if (auto literal = context->DecimalLiteral())
{
auto str = literal->toString();
remove_digit_separators(str);
unsigned long integer = 0;
std::string name = "";
Type *type = nullptr;
bool is_signed = true;

try
{
integer = std::stoul(str, nullptr, base);
}
catch (std::out_of_range &)
{
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str);
}

typedef Type *(*TypeFunction)(llvm::LLVMContext &, const bool &);

struct TypeRules
{
const char *name;
int name_length;
TypeFunction function;
bool is_signed;

unsigned long max;
};

static const std::vector<TypeRules> types = {
{"i8", 2, Type::i8, true, std::numeric_limits<char>::max()},
{"i16", 3, Type::i16, true, std::numeric_limits<short>::max()},
{"i32", 3, Type::i32, true, std::numeric_limits<int>::max()},
{"i64", 3, Type::i64, true, std::numeric_limits<long>::max()},
{"u8", 2, Type::i8, false, std::numeric_limits<unsigned char>::max()},
{"u16", 3, Type::i16, false, std::numeric_limits<unsigned short>::max()},
{"u32", 3, Type::i32, false, std::numeric_limits<unsigned int>::max()},
{"u64", 3, Type::i64, false, std::numeric_limits<unsigned long>::max()},
};

static const std::vector<TypeRules> automatic_types = {
{"i32", 3, Type::i32, true, std::numeric_limits<int>::max()},
{"i64", 3, Type::i64, true, std::numeric_limits<long>::max()},
{"u32", 3, Type::i32, false, std::numeric_limits<unsigned int>::max()},
{"u64", 3, Type::i64, false, std::numeric_limits<unsigned long>::max()},
};

for (const auto &rule : types)
{
if (Helpers::ends_with(str, rule.name))
{
str = str.erase(str.size() - rule.name_length);
name = rule.name;
type = rule.function(scope->context(), rule.is_signed);
is_signed = rule.is_signed;

auto integer = std::stol(str);
if (integer >= rule.max)
{
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str, rule.name);
}

auto type = Type::i64(scope->context());
auto value = llvm::ConstantInt::get(type->get_ref(), integer, true);
break;
}
}

return new Values::Constant("literal_i64", type, value);
if (type == nullptr)
{
for (const auto &rule : automatic_types)
{
if (integer <= rule.max)
{
name = rule.name;
type = rule.function(scope->context(), rule.is_signed);
is_signed = rule.is_signed;
break;
}
}
}

if (type == nullptr)
{
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str);
}

auto value = llvm::ConstantInt::get(llvm::cast<llvm::IntegerType>(type->get_ref()), integer, is_signed);
return new Values::Constant("literal_" + name, type, value);
};

if (auto literal = context->DecimalLiteral())
{
return parse_integer(literal->toString(), 10);
}
else if (context->ZeroLiteral())
{
auto type = Type::i64(scope->context());
auto type = Type::i32(scope->context());
auto value = llvm::ConstantInt::get(type->get_ref(), 0, true);

return new Values::Constant("literal_i64", type, value);
return new Values::Constant("literal_i32", type, value);
}
else if (auto literal = context->HexadecimalLiteral())
{
auto str = literal->toString();
remove_digit_separators(str);

auto integer = std::stol(str, nullptr, 16);

auto type = Type::i64(scope->context());
auto value = llvm::ConstantInt::get(type->get_ref(), integer, false);

return new Values::Constant("literal_i64", type, value);
return parse_integer(literal->toString(), 16);
}
else if (auto literal = context->BinaryLiteral())
{
auto str = literal->toString().substr(2);
remove_digit_separators(str);

auto integer = std::stol(str, nullptr, 2);

auto type = Type::i64(scope->context());
auto value = llvm::ConstantInt::get(type->get_ref(), integer, false);

return new Values::Constant("literal_i64", type, value);
return parse_integer(literal->toString(), 2);
}

return nullptr;
Expand Down
Loading

0 comments on commit 40f4306

Please sign in to comment.