1 // This file defines how to compile integers
6 #include "../environment.h"
7 #include "../stdlib/datatypes.h"
8 #include "../stdlib/integers.h"
9 #include "../stdlib/text.h"
10 #include "../stdlib/util.h"
11 #include "../typecheck.h"
13 #include "compilation.h"
16 Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) {
17 if (ast->tag != Int) {
18 Text_t code = compile(env, ast);
19 type_t *actual_type = get_type(env, ast);
20 if (!promote(env, ast, &code, actual_type, target))
21 code_err(ast, "I couldn't promote this ", type_to_text(actual_type), " to a ", type_to_text(target));
25 if (non_optional(target)->tag == BigIntType) return compile(env, ast);
27 if (target->tag == OptionalType && Match(target, OptionalType)->type) {
28 return promote_to_optional(Match(target, OptionalType)->type,
29 compile_int_to_type(env, ast, Match(target, OptionalType)->type));
32 const char *literal = Match(ast, Int)->str;
33 OptionalInt_t int_val = Int$from_str(literal);
34 if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
37 mpz_init_set_int(i, int_val);
40 if (strncmp(literal, "0x", 2) == 0 || strncmp(literal, "0X", 2) == 0 || strncmp(literal, "0b", 2) == 0) {
41 gmp_asprintf(&c_literal, "0x%ZX", i);
42 } else if (strncmp(literal, "0o", 2) == 0) {
43 gmp_asprintf(&c_literal, "%#Zo", i);
45 gmp_asprintf(&c_literal, "%#Zd", i);
48 if (target->tag == ByteType) {
49 if (mpz_cmp_si(i, UINT8_MAX) <= 0 && mpz_cmp_si(i, 0) >= 0) return Texts("(Byte_t)(", c_literal, ")");
50 code_err(ast, "This integer cannot fit in a byte");
51 } else if (target->tag == NumType) {
52 if (Match(target, NumType)->bits == TYPE_NBITS64) {
53 return Texts("N64(", c_literal, ")");
55 return Texts("N32(", c_literal, ")");
57 } else if (target->tag == IntType) {
58 int64_t target_bits = (int64_t)Match(target, IntType)->bits;
59 switch (target_bits) {
61 if (mpz_cmp_si(i, INT64_MIN) == 0) return Text("I64(INT64_MIN)");
62 if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) return Texts("I64(", c_literal, "L)");
65 if (mpz_cmp_si(i, INT32_MAX) <= 0 && mpz_cmp_si(i, INT32_MIN) >= 0) return Texts("I32(", c_literal, ")");
68 if (mpz_cmp_si(i, INT16_MAX) <= 0 && mpz_cmp_si(i, INT16_MIN) >= 0) return Texts("I16(", c_literal, ")");
71 if (mpz_cmp_si(i, INT8_MAX) <= 0 && mpz_cmp_si(i, INT8_MIN) >= 0) return Texts("I8(", c_literal, ")");
75 code_err(ast, "This integer cannot fit in a ", target_bits, "-bit value");
77 code_err(ast, "I don't know how to compile this to a ", type_to_text(target));
83 Text_t compile_int(ast_t *ast) {
84 const char *str = Match(ast, Int)->str;
85 OptionalInt_t int_val = Int$from_str(str);
86 if (int_val.small == 0) code_err(ast, "Failed to parse this integer");
88 mpz_init_set_int(i, int_val);
89 if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
90 return Texts("I_small(", str, ")");
91 } else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) {
92 return Texts("Int$from_int64(", str, ")");
94 return Texts("Int$from_str(\"", str, "\")");