diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 15:56:38 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-08-24 15:56:38 -0400 |
| commit | e920d306fb51c16fd473033b64aa5ba5c3e07409 (patch) | |
| tree | ab0a7cb47ad050f278981be1e0a4edc19b8daaee /src/compile/integers.c | |
| parent | c62c3200c7078f58b218def14c54bbfd26677069 (diff) | |
Split into more files: promotion, sets, tables, pointers, functions.
Diffstat (limited to 'src/compile/integers.c')
| -rw-r--r-- | src/compile/integers.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/src/compile/integers.c b/src/compile/integers.c new file mode 100644 index 00000000..97c9c61a --- /dev/null +++ b/src/compile/integers.c @@ -0,0 +1,75 @@ +#include <gmp.h> + +#include "../ast.h" +#include "../compile.h" +#include "../environment.h" +#include "../stdlib/datatypes.h" +#include "../stdlib/integers.h" +#include "../stdlib/text.h" +#include "../typecheck.h" +#include "../types.h" +#include "promotion.h" + +Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) { + if (ast->tag != Int) { + Text_t code = compile(env, ast); + type_t *actual_type = get_type(env, ast); + if (!promote(env, ast, &code, actual_type, target)) + code_err(ast, "I couldn't promote this ", type_to_str(actual_type), " to a ", type_to_str(target)); + return code; + } + + if (target->tag == BigIntType) return compile(env, ast); + + if (target->tag == OptionalType && Match(target, OptionalType)->type) + return compile_int_to_type(env, ast, Match(target, OptionalType)->type); + + const char *literal = Match(ast, Int)->str; + OptionalInt_t int_val = Int$from_str(literal); + if (int_val.small == 0) code_err(ast, "Failed to parse this integer"); + + mpz_t i; + mpz_init_set_int(i, int_val); + + char *c_literal; + if (strncmp(literal, "0x", 2) == 0 || strncmp(literal, "0X", 2) == 0 || strncmp(literal, "0b", 2) == 0) { + gmp_asprintf(&c_literal, "0x%ZX", i); + } else if (strncmp(literal, "0o", 2) == 0) { + gmp_asprintf(&c_literal, "%#Zo", i); + } else { + gmp_asprintf(&c_literal, "%#Zd", i); + } + + if (target->tag == ByteType) { + if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0) return Texts("(Byte_t)(", c_literal, ")"); + code_err(ast, "This integer cannot fit in a byte"); + } else if (target->tag == NumType) { + if (Match(target, NumType)->bits == TYPE_NBITS64) { + return Texts("N64(", c_literal, ")"); + } else { + return Texts("N32(", c_literal, ")"); + } + } else if (target->tag == IntType) { + int64_t target_bits = (int64_t)Match(target, IntType)->bits; + switch (target_bits) { + case TYPE_IBITS64: + if (mpz_cmp_si(i, INT64_MIN) == 0) return Text("I64(INT64_MIN)"); + if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) return Texts("I64(", c_literal, "L)"); + break; + case TYPE_IBITS32: + if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0) return Texts("I32(", c_literal, ")"); + break; + case TYPE_IBITS16: + if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) return Texts("I16(", c_literal, ")"); + break; + case TYPE_IBITS8: + if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) return Texts("I8(", c_literal, ")"); + break; + default: break; + } + code_err(ast, "This integer cannot fit in a ", target_bits, "-bit value"); + } else { + code_err(ast, "I don't know how to compile this to a ", type_to_str(target)); + } + return EMPTY_TEXT; +} |
