Lichen

Annotated templates/native/int.c

941:d697508a12c0
2021-10-31 Paul Boddie Introduced a dedicated integer type based on ssize_t. This allows integers to be used for sizes and lengths in native and low-level operations whilst also supporting their storage in the same amount of space as a pointer, thus avoiding the inflation of attributes that might occur if a larger type were chosen.
paul@354 1
/* Native functions for integer operations.
paul@354 2
paul@941 3
Copyright (C) 2016, 2017, 2021 Paul Boddie <paul@boddie.org.uk>
paul@354 4
paul@354 5
This program is free software; you can redistribute it and/or modify it under
paul@354 6
the terms of the GNU General Public License as published by the Free Software
paul@354 7
Foundation; either version 3 of the License, or (at your option) any later
paul@354 8
version.
paul@354 9
paul@354 10
This program is distributed in the hope that it will be useful, but WITHOUT
paul@354 11
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@354 12
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@354 13
details.
paul@354 14
paul@354 15
You should have received a copy of the GNU General Public License along with
paul@354 16
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@354 17
*/
paul@354 18
paul@354 19
#include <math.h>   /* ceil, log10, pow */
paul@583 20
#include <stdio.h>  /* fdopen, snprintf */
paul@354 21
#include <errno.h>  /* errno */
paul@583 22
#include <string.h> /* strlen */
paul@354 23
#include "native/common.h"
paul@354 24
#include "types.h"
paul@354 25
#include "exceptions.h"
paul@354 26
#include "ops.h"
paul@354 27
#include "progconsts.h"
paul@354 28
#include "progops.h"
paul@354 29
#include "progtypes.h"
paul@354 30
#include "main.h"
paul@354 31
paul@354 32
/* Integer operations. */
paul@354 33
paul@767 34
__attr __fn_native_int_is_int(__attr __self, __attr obj)
paul@762 35
{
paul@767 36
    return __INTEGER(obj) ? __builtins___boolean_True : __builtins___boolean_False;
paul@762 37
}
paul@762 38
paul@763 39
__attr __fn_native_int_int_add(__attr __self, __attr self, __attr other)
paul@354 40
{
paul@758 41
    /* self and other interpreted as int */
paul@941 42
    __int i = __TOINT(self);
paul@941 43
    __int j = __TOINT(other);
paul@354 44
paul@354 45
    /* Test for overflow. */
paul@758 46
    if (((i > 0) && (j > 0) && (i > __MAXINT - j)) ||
paul@758 47
        ((i < 0) && (j < 0) && (i < __MININT - j)))
paul@354 48
paul@354 49
        __raise_overflow_error();
paul@354 50
paul@354 51
    /* Return the new integer. */
paul@354 52
    return __new_int(i + j);
paul@354 53
}
paul@354 54
paul@763 55
__attr __fn_native_int_int_sub(__attr __self, __attr self, __attr other)
paul@354 56
{
paul@758 57
    /* self and other interpreted as int */
paul@941 58
    __int i = __TOINT(self);
paul@941 59
    __int j = __TOINT(other);
paul@354 60
paul@354 61
    /* Test for overflow. */
paul@758 62
    if (((i < 0) && (j > 0) && (i < __MININT + j)) ||
paul@758 63
        ((i > 0) && (j < 0) && (i > __MAXINT + j)))
paul@354 64
paul@354 65
        __raise_overflow_error();
paul@354 66
paul@354 67
    /* Return the new integer. */
paul@354 68
    return __new_int(i - j);
paul@354 69
}
paul@354 70
paul@763 71
__attr __fn_native_int_int_mul(__attr __self, __attr self, __attr other)
paul@354 72
{
paul@758 73
    /* self and other interpreted as int */
paul@941 74
    __int i = __TOINT(self);
paul@941 75
    __int j = __TOINT(other);
paul@354 76
paul@354 77
    /* Test for overflow. */
paul@758 78
    if (((i > 0) && (j > 0) && (i > __MAXINT / j)) ||
paul@758 79
        ((i < 0) && (j < 0) && (i > __MAXINT / j)) ||
paul@758 80
        ((i < 0) && (j > 0) && (i < __MININT / j)) ||
paul@758 81
        ((i > 0) && (j < 0) && (j < __MININT / i)))
paul@354 82
paul@354 83
        __raise_overflow_error();
paul@354 84
paul@354 85
    /* Return the new integer. */
paul@354 86
    return __new_int(i * j);
paul@354 87
}
paul@354 88
paul@763 89
__attr __fn_native_int_int_div(__attr __self, __attr self, __attr other)
paul@354 90
{
paul@758 91
    /* self and other interpreted as int */
paul@941 92
    __int i = __TOINT(self);
paul@941 93
    __int j = __TOINT(other);
paul@354 94
paul@354 95
    /* Test for division by zero or overflow. */
paul@354 96
    if (j == 0)
paul@354 97
        __raise_zero_division_error();
paul@758 98
    else if ((j == -1) && (i == __MININT))
paul@354 99
        __raise_overflow_error();
paul@354 100
paul@354 101
    /* Return the new integer. */
paul@354 102
    return __new_int(i / j);
paul@354 103
}
paul@354 104
paul@763 105
__attr __fn_native_int_int_mod(__attr __self, __attr self, __attr other)
paul@354 106
{
paul@758 107
    /* self and other interpreted as int */
paul@941 108
    __int i = __TOINT(self);
paul@941 109
    __int j = __TOINT(other);
paul@354 110
paul@354 111
    /* Test for division by zero or overflow. */
paul@354 112
    if (j == 0)
paul@354 113
        __raise_zero_division_error();
paul@758 114
    else if ((j == -1) && (i == __MININT))
paul@354 115
        __raise_overflow_error();
paul@354 116
paul@354 117
    /* Return the new integer. */
paul@354 118
    return __new_int(i % j);
paul@354 119
}
paul@354 120
paul@763 121
__attr __fn_native_int_int_neg(__attr __self, __attr self)
paul@354 122
{
paul@758 123
    /* self interpreted as int */
paul@941 124
    __int i = __TOINT(self);
paul@354 125
paul@354 126
    /* Test for overflow. */
paul@758 127
    if (i == __MININT)
paul@354 128
        __raise_overflow_error();
paul@354 129
paul@354 130
    /* Return the new integer. */
paul@354 131
    return __new_int(-i);
paul@354 132
}
paul@354 133
paul@763 134
__attr __fn_native_int_int_pow(__attr __self, __attr self, __attr other)
paul@354 135
{
paul@758 136
    /* self and other interpreted as int */
paul@941 137
    __int i = __TOINT(self);
paul@941 138
    __int j = __TOINT(other);
paul@354 139
    int k;
paul@354 140
paul@354 141
    errno = 0;
paul@354 142
    k = (int) pow(i, j);
paul@354 143
paul@354 144
    /* Test for overflow. */
paul@354 145
paul@354 146
    if (errno == ERANGE)
paul@354 147
        __raise_overflow_error();
paul@877 148
    if ((k > 0) && (k > __MAXINT))
paul@877 149
        __raise_overflow_error();
paul@877 150
    if ((k < 0) && (k < __MININT))
paul@877 151
        __raise_overflow_error();
paul@354 152
paul@354 153
    /* Return the new integer. */
paul@354 154
    return __new_int(k);
paul@354 155
}
paul@354 156
paul@763 157
__attr __fn_native_int_int_and(__attr __self, __attr self, __attr other)
paul@354 158
{
paul@758 159
    /* self and other interpreted as int */
paul@941 160
    __int i = __TOINT(self);
paul@941 161
    __int j = __TOINT(other);
paul@354 162
paul@354 163
    /* Return the new integer. */
paul@354 164
    /* NOTE: No overflow test applied. */
paul@354 165
    return __new_int(i & j);
paul@354 166
}
paul@354 167
paul@763 168
__attr __fn_native_int_int_not(__attr __self, __attr self)
paul@354 169
{
paul@758 170
    /* self interpreted as int */
paul@941 171
    __int i = __TOINT(self);
paul@354 172
paul@354 173
    /* Return the new integer. */
paul@354 174
    return __new_int(~i);
paul@354 175
}
paul@354 176
paul@763 177
__attr __fn_native_int_int_or(__attr __self, __attr self, __attr other)
paul@354 178
{
paul@758 179
    /* self and other interpreted as int */
paul@941 180
    __int i = __TOINT(self);
paul@941 181
    __int j = __TOINT(other);
paul@354 182
paul@354 183
    /* Return the new integer. */
paul@354 184
    /* NOTE: No overflow test applied. */
paul@354 185
    return __new_int(i | j);
paul@354 186
}
paul@354 187
paul@763 188
__attr __fn_native_int_int_xor(__attr __self, __attr self, __attr other)
paul@354 189
{
paul@758 190
    /* self and other interpreted as int */
paul@941 191
    __int i = __TOINT(self);
paul@941 192
    __int j = __TOINT(other);
paul@354 193
paul@354 194
    /* Return the new integer. */
paul@354 195
    /* NOTE: No overflow test applied. */
paul@354 196
    return __new_int(i ^ j);
paul@354 197
}
paul@354 198
paul@798 199
__attr __fn_native_int_int_lshift(__attr __self, __attr self, __attr other)
paul@798 200
{
paul@798 201
    /* self and other interpreted as int */
paul@941 202
    __int i = __TOINT(self);
paul@941 203
    __int j = __TOINT(other);
paul@798 204
paul@798 205
    /* Return the new integer. */
paul@798 206
    /* NOTE: No overflow test applied. */
paul@798 207
    return __new_int(i << j);
paul@798 208
}
paul@798 209
paul@798 210
__attr __fn_native_int_int_rshift(__attr __self, __attr self, __attr other)
paul@798 211
{
paul@798 212
    /* self and other interpreted as int */
paul@941 213
    __int i = __TOINT(self);
paul@941 214
    __int j = __TOINT(other);
paul@798 215
paul@798 216
    /* Return the new integer. */
paul@798 217
    /* NOTE: No overflow test applied. */
paul@798 218
    return __new_int(i >> j);
paul@798 219
}
paul@798 220
paul@767 221
__attr __fn_native_int_int_le(__attr __self, __attr self, __attr other)
paul@762 222
{
paul@762 223
    /* self and other interpreted as int */
paul@941 224
    __int i = __TOINT(self);
paul@941 225
    __int j = __TOINT(other);
paul@762 226
paul@762 227
    /* Return a boolean result. */
paul@762 228
    return i <= j ? __builtins___boolean_True : __builtins___boolean_False;
paul@762 229
}
paul@762 230
paul@763 231
__attr __fn_native_int_int_lt(__attr __self, __attr self, __attr other)
paul@354 232
{
paul@758 233
    /* self and other interpreted as int */
paul@941 234
    __int i = __TOINT(self);
paul@941 235
    __int j = __TOINT(other);
paul@354 236
paul@354 237
    /* Return a boolean result. */
paul@354 238
    return i < j ? __builtins___boolean_True : __builtins___boolean_False;
paul@354 239
}
paul@354 240
paul@767 241
__attr __fn_native_int_int_ge(__attr __self, __attr self, __attr other)
paul@762 242
{
paul@762 243
    /* self and other interpreted as int */
paul@941 244
    __int i = __TOINT(self);
paul@941 245
    __int j = __TOINT(other);
paul@762 246
paul@762 247
    /* Return a boolean result. */
paul@762 248
    return i >= j ? __builtins___boolean_True : __builtins___boolean_False;
paul@762 249
}
paul@762 250
paul@763 251
__attr __fn_native_int_int_gt(__attr __self, __attr self, __attr other)
paul@354 252
{
paul@758 253
    /* self and other interpreted as int */
paul@941 254
    __int i = __TOINT(self);
paul@941 255
    __int j = __TOINT(other);
paul@354 256
paul@354 257
    /* Return a boolean result. */
paul@354 258
    return i > j ? __builtins___boolean_True : __builtins___boolean_False;
paul@354 259
}
paul@354 260
paul@763 261
__attr __fn_native_int_int_eq(__attr __self, __attr self, __attr other)
paul@354 262
{
paul@758 263
    /* self and other interpreted as int */
paul@941 264
    __int i = __TOINT(self);
paul@941 265
    __int j = __TOINT(other);
paul@354 266
paul@354 267
    /* Return a boolean result. */
paul@354 268
    return i == j ? __builtins___boolean_True : __builtins___boolean_False;
paul@354 269
}
paul@354 270
paul@763 271
__attr __fn_native_int_int_ne(__attr __self, __attr self, __attr other)
paul@354 272
{
paul@758 273
    /* self and other interpreted as int */
paul@941 274
    __int i = __TOINT(self);
paul@941 275
    __int j = __TOINT(other);
paul@354 276
paul@354 277
    /* Return a boolean result. */
paul@354 278
    return i != j ? __builtins___boolean_True : __builtins___boolean_False;
paul@354 279
}
paul@354 280
paul@763 281
__attr __fn_native_int_int_str(__attr __self, __attr self)
paul@354 282
{
paul@758 283
    /* self interpreted as int */
paul@941 284
    __int i = __TOINT(self);
paul@763 285
paul@354 286
    /* Employ a buffer big enough to fit the largest integer plus an extra
paul@354 287
       character, a minus sign, and the null terminator. */
paul@758 288
    unsigned int n = (int) log10(__MAXINT) + 3;
paul@354 289
    char *s = (char *) __ALLOCATE(n, sizeof(char));
paul@354 290
paul@941 291
    snprintf(s, n, "%ld", i);
paul@354 292
paul@354 293
    /* Return a new string. */
paul@583 294
    return __new_str(s, strlen(s));
paul@354 295
}
paul@354 296
paul@354 297
/* Module initialisation. */
paul@354 298
paul@354 299
void __main_native_int()
paul@354 300
{
paul@354 301
}