Skip to content

Commit 40f4306

Browse files
committed
Implement more control over decimal numbers
1 parent 24ce1e4 commit 40f4306

File tree

6 files changed

+551
-431
lines changed

6 files changed

+551
-431
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#pragma once
2+
3+
#include <Sand/Exceptions/CompilationException.hpp>
4+
#include <Sand/Type.hpp>
5+
6+
namespace Sand
7+
{
8+
class NumberOutOfRangeException : public CompilationException
9+
{
10+
public:
11+
NumberOutOfRangeException(const fs::path &source, antlr4::Token *token, const std::string &number) : CompilationException(source, "Number out of range: '" + number + "'.", token) {}
12+
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) {}
13+
};
14+
} // namespace Sand

include/Sand/Type.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,27 +293,27 @@ class Type : public Name
293293
return llvm::Type::getVoidTy(context);
294294
}
295295

296-
static llvm::Type *llvm_i1(llvm::LLVMContext &context)
296+
static llvm::IntegerType *llvm_i1(llvm::LLVMContext &context)
297297
{
298298
return llvm::Type::getInt1Ty(context);
299299
}
300300

301-
static llvm::Type *llvm_i8(llvm::LLVMContext &context)
301+
static llvm::IntegerType *llvm_i8(llvm::LLVMContext &context)
302302
{
303303
return llvm::Type::getInt8Ty(context);
304304
}
305305

306-
static llvm::Type *llvm_i16(llvm::LLVMContext &context)
306+
static llvm::IntegerType *llvm_i16(llvm::LLVMContext &context)
307307
{
308308
return llvm::Type::getInt16Ty(context);
309309
}
310310

311-
static llvm::Type *llvm_i32(llvm::LLVMContext &context)
311+
static llvm::IntegerType *llvm_i32(llvm::LLVMContext &context)
312312
{
313313
return llvm::Type::getInt32Ty(context);
314314
}
315315

316-
static llvm::Type *llvm_i64(llvm::LLVMContext &context)
316+
static llvm::IntegerType *llvm_i64(llvm::LLVMContext &context)
317317
{
318318
return llvm::Type::getInt64Ty(context);
319319
}

src/grammar/SandLexer.g4

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,33 @@ CharLiteral: '\'' CharChar+ '\'';
126126
fragment StringChar: ~ ["\r\n] | Escape;
127127
fragment CharChar: ~ ['\r\n] | Escape;
128128
129-
DecimalLiteral: NONZERODIGIT (DIGITSEPARATOR? DIGIT)*;
129+
DecimalLiteral:
130+
NONZERODIGIT (DIGITSEPARATOR? DIGIT)* IntegerType?;
130131
131132
FloatingLiteral:
132133
(DecimalLiteral | ZeroLiteral)? '.' DIGIT (
133134
DIGITSEPARATOR? DIGIT
134135
)*;
135136
136-
ZeroLiteral: '0';
137+
ZeroLiteral: '0' IntegerType?;
137138
138139
HexadecimalLiteral: ('0x' | '0X') HEXADECIMALDIGIT (
139140
DIGITSEPARATOR? HEXADECIMALDIGIT
140-
)*;
141+
)* IntegerType?;
141142
142143
BinaryLiteral: ('0b' | '0B') BINARYDIGIT (
143144
DIGITSEPARATOR? BINARYDIGIT
144-
)*;
145+
)* IntegerType?;
146+
147+
fragment IntegerType:
148+
'i8'
149+
| 'i16'
150+
| 'i32'
151+
| 'i64'
152+
| 'u8'
153+
| 'u16'
154+
| 'u32'
155+
| 'u64';
145156
146157
// Comments
147158
Comment: '//' CommentLine* -> skip;

src/grammar/Visitor.hpp

Lines changed: 93 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <Sand/Exceptions/NotAClassOrNamespaceException.hpp>
4848
#include <Sand/Exceptions/NotAGenericException.hpp>
4949
#include <Sand/Exceptions/NotAPointerException.hpp>
50+
#include <Sand/Exceptions/NumberOutOfRangeException.hpp>
5051
#include <Sand/Exceptions/OpaqueTypeNotAllowedException.hpp>
5152
#include <Sand/Exceptions/PropertyNotFoundException.hpp>
5253
#include <Sand/Exceptions/ReturnOutsideOfFunctionException.hpp>
@@ -58,7 +59,9 @@
5859

5960
#include <Sand/filesystem.hpp>
6061

62+
#include <limits>
6163
#include <regex>
64+
#include <tuple>
6265

6366
namespace Sand
6467
{
@@ -3315,53 +3318,115 @@ class Visitor
33153318
{
33163319
auto scope = this->scopes.top();
33173320

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

3323-
if (auto literal = context->DecimalLiteral())
3324-
{
3325-
auto str = literal->toString();
3326-
remove_digit_separators(str);
3325+
unsigned long integer = 0;
3326+
std::string name = "";
3327+
Type *type = nullptr;
3328+
bool is_signed = true;
3329+
3330+
try
3331+
{
3332+
integer = std::stoul(str, nullptr, base);
3333+
}
3334+
catch (std::out_of_range &)
3335+
{
3336+
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str);
3337+
}
3338+
3339+
typedef Type *(*TypeFunction)(llvm::LLVMContext &, const bool &);
3340+
3341+
struct TypeRules
3342+
{
3343+
const char *name;
3344+
int name_length;
3345+
TypeFunction function;
3346+
bool is_signed;
3347+
3348+
unsigned long max;
3349+
};
3350+
3351+
static const std::vector<TypeRules> types = {
3352+
{"i8", 2, Type::i8, true, std::numeric_limits<char>::max()},
3353+
{"i16", 3, Type::i16, true, std::numeric_limits<short>::max()},
3354+
{"i32", 3, Type::i32, true, std::numeric_limits<int>::max()},
3355+
{"i64", 3, Type::i64, true, std::numeric_limits<long>::max()},
3356+
{"u8", 2, Type::i8, false, std::numeric_limits<unsigned char>::max()},
3357+
{"u16", 3, Type::i16, false, std::numeric_limits<unsigned short>::max()},
3358+
{"u32", 3, Type::i32, false, std::numeric_limits<unsigned int>::max()},
3359+
{"u64", 3, Type::i64, false, std::numeric_limits<unsigned long>::max()},
3360+
};
3361+
3362+
static const std::vector<TypeRules> automatic_types = {
3363+
{"i32", 3, Type::i32, true, std::numeric_limits<int>::max()},
3364+
{"i64", 3, Type::i64, true, std::numeric_limits<long>::max()},
3365+
{"u32", 3, Type::i32, false, std::numeric_limits<unsigned int>::max()},
3366+
{"u64", 3, Type::i64, false, std::numeric_limits<unsigned long>::max()},
3367+
};
3368+
3369+
for (const auto &rule : types)
3370+
{
3371+
if (Helpers::ends_with(str, rule.name))
3372+
{
3373+
str = str.erase(str.size() - rule.name_length);
3374+
name = rule.name;
3375+
type = rule.function(scope->context(), rule.is_signed);
3376+
is_signed = rule.is_signed;
33273377

3328-
auto integer = std::stol(str);
3378+
if (integer >= rule.max)
3379+
{
3380+
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str, rule.name);
3381+
}
33293382

3330-
auto type = Type::i64(scope->context());
3331-
auto value = llvm::ConstantInt::get(type->get_ref(), integer, true);
3383+
break;
3384+
}
3385+
}
33323386

3333-
return new Values::Constant("literal_i64", type, value);
3387+
if (type == nullptr)
3388+
{
3389+
for (const auto &rule : automatic_types)
3390+
{
3391+
if (integer <= rule.max)
3392+
{
3393+
name = rule.name;
3394+
type = rule.function(scope->context(), rule.is_signed);
3395+
is_signed = rule.is_signed;
3396+
break;
3397+
}
3398+
}
3399+
}
3400+
3401+
if (type == nullptr)
3402+
{
3403+
throw NumberOutOfRangeException(this->files.top(), context->getStart(), str);
3404+
}
3405+
3406+
auto value = llvm::ConstantInt::get(llvm::cast<llvm::IntegerType>(type->get_ref()), integer, is_signed);
3407+
return new Values::Constant("literal_" + name, type, value);
3408+
};
3409+
3410+
if (auto literal = context->DecimalLiteral())
3411+
{
3412+
return parse_integer(literal->toString(), 10);
33343413
}
33353414
else if (context->ZeroLiteral())
33363415
{
3337-
auto type = Type::i64(scope->context());
3416+
auto type = Type::i32(scope->context());
33383417
auto value = llvm::ConstantInt::get(type->get_ref(), 0, true);
33393418

3340-
return new Values::Constant("literal_i64", type, value);
3419+
return new Values::Constant("literal_i32", type, value);
33413420
}
33423421
else if (auto literal = context->HexadecimalLiteral())
33433422
{
33443423
auto str = literal->toString();
3345-
remove_digit_separators(str);
3346-
3347-
auto integer = std::stol(str, nullptr, 16);
3348-
3349-
auto type = Type::i64(scope->context());
3350-
auto value = llvm::ConstantInt::get(type->get_ref(), integer, false);
3351-
3352-
return new Values::Constant("literal_i64", type, value);
3424+
return parse_integer(literal->toString(), 16);
33533425
}
33543426
else if (auto literal = context->BinaryLiteral())
33553427
{
33563428
auto str = literal->toString().substr(2);
3357-
remove_digit_separators(str);
3358-
3359-
auto integer = std::stol(str, nullptr, 2);
3360-
3361-
auto type = Type::i64(scope->context());
3362-
auto value = llvm::ConstantInt::get(type->get_ref(), integer, false);
3363-
3364-
return new Values::Constant("literal_i64", type, value);
3429+
return parse_integer(literal->toString(), 2);
33653430
}
33663431

33673432
return nullptr;

0 commit comments

Comments
 (0)