|
47 | 47 | #include <Sand/Exceptions/NotAClassOrNamespaceException.hpp>
|
48 | 48 | #include <Sand/Exceptions/NotAGenericException.hpp>
|
49 | 49 | #include <Sand/Exceptions/NotAPointerException.hpp>
|
| 50 | +#include <Sand/Exceptions/NumberOutOfRangeException.hpp> |
50 | 51 | #include <Sand/Exceptions/OpaqueTypeNotAllowedException.hpp>
|
51 | 52 | #include <Sand/Exceptions/PropertyNotFoundException.hpp>
|
52 | 53 | #include <Sand/Exceptions/ReturnOutsideOfFunctionException.hpp>
|
|
58 | 59 |
|
59 | 60 | #include <Sand/filesystem.hpp>
|
60 | 61 |
|
| 62 | +#include <limits> |
61 | 63 | #include <regex>
|
| 64 | +#include <tuple> |
62 | 65 |
|
63 | 66 | namespace Sand
|
64 | 67 | {
|
@@ -3315,53 +3318,115 @@ class Visitor
|
3315 | 3318 | {
|
3316 | 3319 | auto scope = this->scopes.top();
|
3317 | 3320 |
|
3318 |
| - const auto remove_digit_separators = [](std::string &str) { |
| 3321 | + const auto parse_integer = [&](std::string str, int base = 10) -> Values::Constant * { |
3319 | 3322 | str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
|
3320 | 3323 | str.erase(std::remove(str.begin(), str.end(), '\''), str.end());
|
3321 |
| - }; |
3322 | 3324 |
|
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; |
3327 | 3377 |
|
3328 |
| - auto integer = std::stol(str); |
| 3378 | + if (integer >= rule.max) |
| 3379 | + { |
| 3380 | + throw NumberOutOfRangeException(this->files.top(), context->getStart(), str, rule.name); |
| 3381 | + } |
3329 | 3382 |
|
3330 |
| - auto type = Type::i64(scope->context()); |
3331 |
| - auto value = llvm::ConstantInt::get(type->get_ref(), integer, true); |
| 3383 | + break; |
| 3384 | + } |
| 3385 | + } |
3332 | 3386 |
|
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); |
3334 | 3413 | }
|
3335 | 3414 | else if (context->ZeroLiteral())
|
3336 | 3415 | {
|
3337 |
| - auto type = Type::i64(scope->context()); |
| 3416 | + auto type = Type::i32(scope->context()); |
3338 | 3417 | auto value = llvm::ConstantInt::get(type->get_ref(), 0, true);
|
3339 | 3418 |
|
3340 |
| - return new Values::Constant("literal_i64", type, value); |
| 3419 | + return new Values::Constant("literal_i32", type, value); |
3341 | 3420 | }
|
3342 | 3421 | else if (auto literal = context->HexadecimalLiteral())
|
3343 | 3422 | {
|
3344 | 3423 | 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); |
3353 | 3425 | }
|
3354 | 3426 | else if (auto literal = context->BinaryLiteral())
|
3355 | 3427 | {
|
3356 | 3428 | 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); |
3365 | 3430 | }
|
3366 | 3431 |
|
3367 | 3432 | return nullptr;
|
|
0 commit comments