1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
// This file defines how to compile integers
#include <gmp.h>
#include "../ast.h"
#include "../environment.h"
#include "../stdlib/datatypes.h"
#include "../stdlib/integers.h"
#include "../stdlib/text.h"
#include "../stdlib/util.h"
#include "../typecheck.h"
#include "../types.h"
#include "compilation.h"
public
Text_t compile_int_to_type(env_t *env, ast_t *ast, type_t *target) {
if (ast->tag != Integer) {
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_text(actual_type), " to a ", type_to_text(target));
return code;
}
if (non_optional(target)->tag == BigIntType) return compile(env, ast);
if (target->tag == OptionalType && Match(target, OptionalType)->type) {
return Texts("((", compile_type(target),
"){.value=", compile_int_to_type(env, ast, Match(target, OptionalType)->type),
", .has_value=true})");
}
OptionalInt_t int_val = Match(ast, Integer)->i;
Text_t source = ast_source(ast);
mpz_t i;
mpz_init_set_int(i, int_val);
char *c_literal;
if (Text$has(source, Text("0x")) || Text$has(source, Text("0X")) || Text$has(source, Text("0b"))) {
gmp_asprintf(&c_literal, "0x%ZX", i);
} else if (Text$has(source, Text("0o"))) {
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 == FloatType) {
if (Match(target, FloatType)->bits == TYPE_NBITS64) {
return Texts("F64(", c_literal, ")");
} else {
return Texts("F32(", 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_text(target));
}
return EMPTY_TEXT;
}
public
Text_t compile_int(ast_t *ast) {
Int_t int_val = Match(ast, Integer)->i;
mpz_t i;
mpz_init_set_int(i, int_val);
OptionalText_t source = ast_source(ast);
char *c_literal;
if (Text$has(source, Text("0x")) || Text$has(source, Text("0X")) || Text$has(source, Text("0b"))) {
gmp_asprintf(&c_literal, "0x%ZX", i);
} else if (Text$has(source, Text("0o"))) {
gmp_asprintf(&c_literal, "%#Zo", i);
} else {
gmp_asprintf(&c_literal, "%#Zd", i);
}
// TODO: preserve base
if (mpz_cmpabs_ui(i, BIGGEST_SMALL_INT) <= 0) {
return Texts("I_small(", c_literal, ")");
} else if (mpz_cmp_si(i, INT64_MAX) <= 0 && mpz_cmp_si(i, INT64_MIN) >= 0) {
return Texts("Int$from_int64(", c_literal, ")");
} else if (source.tag == TEXT_NONE) {
return Texts("Int$from_str(\"", int_val, "\")");
} else {
source = Text$replace(source, Text("("), Text(""));
source = Text$replace(source, Text(")"), Text(""));
source = Text$replace(source, Text(" "), Text(""));
source = Text$replace(source, Text("_"), Text(""));
return Texts("Int$from_str(\"", source, "\")");
}
}
|