-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCore.scope
184 lines (143 loc) · 3.18 KB
/
Core.scope
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import "LowLevel/Floats";
import "LowLevel/Limits";
import "Math/Rounding";
import "Math/Core";
using Math;
using LowLevel;
/%
@noalloc: This function does not use string concatenation.
Prints @"s" into `stdout` along with a new-line.
%/
func void println(str s) {
print(s);
print("\n");
}
/%
@asm
Returns the user input from `stdin` until a new line.
The new line is not included in the final string.
The program will pause until the user finishes the input.
%/
func str input() {
str o = "";
assembly {
call input
vlist_set $o$
}
ret o;
}
/%
@asm
Stops the program for @"time" seconds.
@"time" will be clamped between 0 and @"INT_MAX".
%/
func void sleep(dec time) {
// Special cases
if (time <= 0.0) {
ret;
}
if (time > INT_MAX -> dec) {
time = INT_MAX -> dec;
}
// Convert input to seconds and nanoseconds
dec rounded = floor(time);
int seconds = rounded -> int;
int nano = (time - rounded) * 1'000'000'000.0 -> int;
// Call syscall
assembly {
vlist_get rdi, $seconds$
vlist_get rsi, $nano$
call sleep
}
}
/%
Converts @"b" into a string.
Returns `"true"` or `"false"`.
%/
func str boolToStr(bool b) {
if (b) {
ret "true";
}
ret "false";
}
/%
Converts integer @"num" into a string.
Returns the number in a basic format without any commas.
Prepends a `-` if negative.
%/
func str intToStr(int num) {
// If we don't do this, this will return ""
if (num == 0) {
ret "0";
}
str out = "";
bool neg = num < 0;
// Deal with negatives
if (neg) {
num = -num;
}
// Add digits (in reverse order)
while (num > 0) {
out = "0123456789"[num % 10] + out;
num /= 10;
}
// Add negative sign (if negative)
if (neg) {
out = "-" + out;
}
ret out;
}
/%
Converts decimal @"num" into a string.
Returns the number a normal decimal format *or* scientific notation.
Prepends a `-` if negative.
%/
func str decToStr(dec num) {
// Special cases
if (num == 0.0) {
ret "0.0";
}
if (num == infinity) {
ret "infinity";
}
if (num == -infinity) {
ret "-infinity";
}
// Normal cases
// Deal with negatives
bool neg = num < 0.0;
if (neg) {
num = -num;
}
int exponent = exponentPart(num) - 1023;
str out = "NaN";
if (exponent < 39 & exponent > -21) { // The limit for a normal decimal representation
// Seperate the whole and decimal part
dec wholePart = floor(num);
dec decimalPart = num - wholePart;
str whole = intToStr(wholePart -> int);
str decimal = intToStr(decimalPart * 1'000'000.0 -> int);
// Pad with zeros on left
while (decimal.length < 6) {
decimal = "0" + decimal;
}
out = whole + "." + decimal;
} else if (exponent != 1024) { // Represent in scientific notation
dec realMantissa = mantissaPartAsDec(num);
// Convert the base 2 scientific to base 10
// x * 2 ^ y -> x * 10 ^ y
// ln(2) / ln(10) = 0.301029995663981
// Also add a little bit for floating point inaccuracy
dec result =
log10(realMantissa) +
(exponent -> dec) * 0.301029995663981 +
0.0000000000001;
dec newExponent = floor(result);
dec newMantissa = pow(10.0, result - newExponent);
out = decToStr(newMantissa) + " * 10 ^ " + intToStr(newExponent -> int);
}
if (neg) {
out = "-" + out;
}
ret out;
}