1 #include <stdlib.h> /* calloc, exit, realloc */ 2 #include <unistd.h> /* read, write */ 3 #include <math.h> /* ceil, log10, pow */ 4 #include <string.h> /* strcmp, strncpy, strlen */ 5 #include <stdio.h> /* snprintf */ 6 #include "types.h" 7 #include "exceptions.h" 8 #include "ops.h" 9 #include "progconsts.h" 10 #include "progops.h" 11 #include "progtypes.h" 12 #include "main.h" 13 14 /* Utility functions. */ 15 16 inline __attr __new_int(int i) 17 { 18 /* Create a new integer and mutate the __data__ attribute. */ 19 __attr attr = __new(&__InstanceTable___builtins___int_int, &__builtins___int_int, sizeof(__obj___builtins___int_int)); 20 attr.value->attrs[__pos___data__].intvalue = i; 21 return attr; 22 } 23 24 inline __attr __new_str(char *s) 25 { 26 /* Create a new string and mutate the __data__ attribute. */ 27 __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string)); 28 attr.value->attrs[__pos___data__].strvalue = s; 29 return attr; 30 } 31 32 /* Native functions. */ 33 34 __attr __fn_native__exit(__attr __args[]) 35 { 36 __attr * const status = &__args[1]; 37 38 exit(__load_via_object(status->value, __pos___data__).intvalue); 39 return __builtins___none_None; 40 } 41 42 __attr __fn_native__get_argv(__attr __args[]) 43 { 44 __attr * const status = &__args[1]; 45 46 /* NOTE: To be written. */ 47 return __builtins___none_None; 48 } 49 50 __attr __fn_native__get_path(__attr __args[]) 51 { 52 __attr * const status = &__args[1]; 53 54 /* NOTE: To be written. */ 55 return __builtins___none_None; 56 } 57 58 __attr __fn_native__is(__attr __args[]) 59 { 60 __attr * const x = &__args[1]; 61 __attr * const y = &__args[2]; 62 63 return x->value == y->value ? __builtins___boolean_True : __builtins___boolean_False; 64 } 65 66 __attr __fn_native__is_not(__attr __args[]) 67 { 68 __attr * const x = &__args[1]; 69 __attr * const y = &__args[2]; 70 71 return x->value != y->value ? __builtins___boolean_True : __builtins___boolean_False; 72 } 73 74 __attr __fn_native__int_add(__attr __args[]) 75 { 76 __attr * const self = &__args[1]; 77 __attr * const other = &__args[2]; 78 /* self.__data__ and other.__data__ interpreted as int */ 79 int i = __load_via_object(self->value, __pos___data__).intvalue; 80 int j = __load_via_object(other->value, __pos___data__).intvalue; 81 82 /* Return the new integer. */ 83 /* NOTE: No overflow test applied. */ 84 return __new_int(i + j); 85 } 86 87 __attr __fn_native__int_sub(__attr __args[]) 88 { 89 __attr * const self = &__args[1]; 90 __attr * const other = &__args[2]; 91 /* self.__data__ and other.__data__ interpreted as int */ 92 int i = __load_via_object(self->value, __pos___data__).intvalue; 93 int j = __load_via_object(other->value, __pos___data__).intvalue; 94 95 /* Return the new integer. */ 96 /* NOTE: No overflow test applied. */ 97 return __new_int(i - j); 98 } 99 100 __attr __fn_native__int_mul(__attr __args[]) 101 { 102 __attr * const self = &__args[1]; 103 __attr * const other = &__args[2]; 104 /* self.__data__ and other.__data__ interpreted as int */ 105 int i = __load_via_object(self->value, __pos___data__).intvalue; 106 int j = __load_via_object(other->value, __pos___data__).intvalue; 107 108 /* Return the new integer. */ 109 /* NOTE: No overflow test applied. */ 110 return __new_int(i * j); 111 } 112 113 __attr __fn_native__int_div(__attr __args[]) 114 { 115 __attr * const self = &__args[1]; 116 __attr * const other = &__args[2]; 117 /* self.__data__ and other.__data__ interpreted as int */ 118 int i = __load_via_object(self->value, __pos___data__).intvalue; 119 int j = __load_via_object(other->value, __pos___data__).intvalue; 120 121 /* Return the new integer. */ 122 /* NOTE: No overflow test applied. */ 123 return __new_int(i / j); 124 } 125 126 __attr __fn_native__int_mod(__attr __args[]) 127 { 128 __attr * const self = &__args[1]; 129 __attr * const other = &__args[2]; 130 /* self.__data__ and other.__data__ interpreted as int */ 131 int i = __load_via_object(self->value, __pos___data__).intvalue; 132 int j = __load_via_object(other->value, __pos___data__).intvalue; 133 134 /* Return the new integer. */ 135 /* NOTE: No overflow test applied. */ 136 return __new_int(i % j); 137 } 138 139 __attr __fn_native__int_neg(__attr __args[]) 140 { 141 __attr * const self = &__args[1]; 142 /* self.__data__ interpreted as int */ 143 int i = __load_via_object(self->value, __pos___data__).intvalue; 144 145 /* Return the new integer. */ 146 return __new_int(-i); 147 } 148 149 __attr __fn_native__int_pow(__attr __args[]) 150 { 151 __attr * const self = &__args[1]; 152 __attr * const other = &__args[2]; 153 /* self.__data__ and other.__data__ interpreted as int */ 154 int i = __load_via_object(self->value, __pos___data__).intvalue; 155 int j = __load_via_object(other->value, __pos___data__).intvalue; 156 157 /* Return the new integer. */ 158 /* NOTE: No overflow test applied. */ 159 return __new_int((int) pow(i, j)); 160 } 161 162 __attr __fn_native__int_and(__attr __args[]) 163 { 164 __attr * const self = &__args[1]; 165 __attr * const other = &__args[2]; 166 /* self.__data__ and other.__data__ interpreted as int */ 167 int i = __load_via_object(self->value, __pos___data__).intvalue; 168 int j = __load_via_object(other->value, __pos___data__).intvalue; 169 170 /* Return the new integer. */ 171 /* NOTE: No overflow test applied. */ 172 return __new_int(i & j); 173 } 174 175 __attr __fn_native__int_or(__attr __args[]) 176 { 177 __attr * const self = &__args[1]; 178 __attr * const other = &__args[2]; 179 /* self.__data__ and other.__data__ interpreted as int */ 180 int i = __load_via_object(self->value, __pos___data__).intvalue; 181 int j = __load_via_object(other->value, __pos___data__).intvalue; 182 183 /* Return the new integer. */ 184 /* NOTE: No overflow test applied. */ 185 return __new_int(i | j); 186 } 187 188 __attr __fn_native__int_xor(__attr __args[]) 189 { 190 __attr * const self = &__args[1]; 191 __attr * const other = &__args[2]; 192 /* self.__data__ and other.__data__ interpreted as int */ 193 int i = __load_via_object(self->value, __pos___data__).intvalue; 194 int j = __load_via_object(other->value, __pos___data__).intvalue; 195 196 /* Return the new integer. */ 197 /* NOTE: No overflow test applied. */ 198 return __new_int(i ^ j); 199 } 200 201 __attr __fn_native__int_lt(__attr __args[]) 202 { 203 __attr * const self = &__args[1]; 204 __attr * const other = &__args[2]; 205 /* self.__data__ and other.__data__ interpreted as int */ 206 int i = __load_via_object(self->value, __pos___data__).intvalue; 207 int j = __load_via_object(other->value, __pos___data__).intvalue; 208 209 /* Return a boolean result. */ 210 return i < j ? __builtins___boolean_True : __builtins___boolean_False; 211 } 212 213 __attr __fn_native__int_gt(__attr __args[]) 214 { 215 __attr * const self = &__args[1]; 216 __attr * const other = &__args[2]; 217 /* self.__data__ and other.__data__ interpreted as int */ 218 int i = __load_via_object(self->value, __pos___data__).intvalue; 219 int j = __load_via_object(other->value, __pos___data__).intvalue; 220 221 /* Return a boolean result. */ 222 return i > j ? __builtins___boolean_True : __builtins___boolean_False; 223 } 224 225 __attr __fn_native__int_eq(__attr __args[]) 226 { 227 __attr * const self = &__args[1]; 228 __attr * const other = &__args[2]; 229 /* self.__data__ and other.__data__ interpreted as int */ 230 int i = __load_via_object(self->value, __pos___data__).intvalue; 231 int j = __load_via_object(other->value, __pos___data__).intvalue; 232 233 /* Return a boolean result. */ 234 return i == j ? __builtins___boolean_True : __builtins___boolean_False; 235 } 236 237 __attr __fn_native__int_ne(__attr __args[]) 238 { 239 __attr * const self = &__args[1]; 240 __attr * const other = &__args[2]; 241 /* self.__data__ and other.__data__ interpreted as int */ 242 int i = __load_via_object(self->value, __pos___data__).intvalue; 243 int j = __load_via_object(other->value, __pos___data__).intvalue; 244 245 /* Return a boolean result. */ 246 return i != j ? __builtins___boolean_True : __builtins___boolean_False; 247 } 248 249 __attr __fn_native__int_str(__attr __args[]) 250 { 251 __attr * const self = &__args[1]; 252 /* self.__data__ interpreted as int */ 253 int i = __load_via_object(self->value, __pos___data__).intvalue; 254 int n = i != 0 ? (int) ceil(log10(i+1)) + 1 : 2; 255 char *s = calloc(n, sizeof(char)); 256 257 if (i < 0) n++; 258 snprintf(s, n, "%d", i); 259 260 /* Return a new string. */ 261 return __new_str(s); 262 } 263 264 __attr __fn_native__str_add(__attr __args[]) 265 { 266 __attr * const self = &__args[1]; 267 __attr * const other = &__args[2]; 268 /* self.__data__, other.__data__ interpreted as string */ 269 char *s = __load_via_object(self->value, __pos___data__).strvalue; 270 char *o = __load_via_object(other->value, __pos___data__).strvalue; 271 int n = strlen(s) + strlen(o) + 1; 272 char *r = calloc(n, sizeof(char)); 273 274 strncpy(r, s, n); 275 strncpy(r + strlen(s), o, n - strlen(s)); 276 277 /* Return a new string. */ 278 return __new_str(r); 279 } 280 281 __attr __fn_native__str_lt(__attr __args[]) 282 { 283 __attr * const self = &__args[1]; 284 __attr * const other = &__args[2]; 285 /* self.__data__, other.__data__ interpreted as string */ 286 char *s = __load_via_object(self->value, __pos___data__).strvalue; 287 char *o = __load_via_object(other->value, __pos___data__).strvalue; 288 289 /* NOTE: Using simple byte-level string operations. */ 290 return strcmp(s, o) < 0 ? __builtins___boolean_True : __builtins___boolean_False; 291 } 292 293 __attr __fn_native__str_gt(__attr __args[]) 294 { 295 __attr * const self = &__args[1]; 296 __attr * const other = &__args[2]; 297 /* self.__data__, other.__data__ interpreted as string */ 298 char *s = __load_via_object(self->value, __pos___data__).strvalue; 299 char *o = __load_via_object(other->value, __pos___data__).strvalue; 300 301 /* NOTE: Using simple byte-level string operations. */ 302 return strcmp(s, o) > 0 ? __builtins___boolean_True : __builtins___boolean_False; 303 } 304 305 __attr __fn_native__str_eq(__attr __args[]) 306 { 307 __attr * const self = &__args[1]; 308 __attr * const other = &__args[2]; 309 /* self.__data__, other.__data__ interpreted as string */ 310 char *s = __load_via_object(self->value, __pos___data__).strvalue; 311 char *o = __load_via_object(other->value, __pos___data__).strvalue; 312 313 /* NOTE: Using simple byte-level string operations. */ 314 return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False; 315 } 316 317 __attr __fn_native__str_len(__attr __args[]) 318 { 319 __attr * const self = &__args[1]; 320 /* self.__data__ interpreted as string */ 321 char *s = __load_via_object(self->value, __pos___data__).strvalue; 322 323 /* Return the new integer. */ 324 return __new_int(strlen(s)); 325 } 326 327 __attr __fn_native__str_nonempty(__attr __args[]) 328 { 329 __attr * const self = &__args[1]; 330 /* self.__data__ interpreted as string */ 331 char *s = __load_via_object(self->value, __pos___data__).strvalue; 332 333 return strlen(s) ? __builtins___boolean_True : __builtins___boolean_False; 334 } 335 336 __attr __fn_native__list_init(__attr __args[]) 337 { 338 __attr * const size = &__args[1]; 339 /* size.__data__ interpreted as int */ 340 unsigned int n = __load_via_object(size->value, __pos___data__).intvalue; 341 342 /* Allocate space for the list. */ 343 __fragment *data = calloc(1, __FRAGMENT_SIZE(n)); 344 __attr attr = {0, .data=data}; 345 346 /* The initial capacity is the same as the given size. */ 347 data->size = 0; 348 data->capacity = n; 349 return attr; 350 } 351 352 __attr __fn_native__list_append(__attr __args[]) 353 { 354 __attr * const self = &__args[1]; 355 __attr * const value = &__args[2]; 356 /* self.__data__ interpreted as list */ 357 __fragment *data = __load_via_object(self->value, __pos___data__).data; 358 unsigned int size = data->size, capacity = data->capacity; 359 unsigned int n; 360 361 /* Re-allocate the fragment if the capacity has been reached. */ 362 if (size >= capacity) 363 { 364 /* NOTE: Consider various restrictions on capacity increases. */ 365 n = capacity ? capacity * 2 : 1; 366 data = realloc(data, __FRAGMENT_SIZE(n)); 367 data->capacity = n; 368 } 369 370 /* Insert the new element and increment the list size. */ 371 data->attrs[size] = *value; 372 data->size = size + 1; 373 return __builtins___none_None; 374 } 375 376 __attr __fn_native__list_concat(__attr __args[]) 377 { 378 __attr * const self = &__args[1]; 379 __attr * const __other = &__args[2]; 380 /* self.__data__, __other.__data__ interpreted as list */ 381 __fragment *data = __load_via_object(self->value, __pos___data__).data; 382 __fragment *other_data = __load_via_object(__other->value, __pos___data__).data; 383 unsigned int size = data->size, capacity = data->capacity; 384 unsigned int other_size = other_data->size; 385 unsigned int i, j, n; 386 387 /* Re-allocate the fragment if the capacity has been reached. */ 388 if (size + other_size >= capacity) 389 { 390 n = size + other_size; 391 data = realloc(data, __FRAGMENT_SIZE(n)); 392 data->capacity = n; 393 } 394 395 /* Copy the elements from the other list and increment the list size. */ 396 for (i = size, j = 0; j < other_size; i++, j++) 397 data->attrs[i] = other_data->attrs[j]; 398 data->size = n; 399 return __builtins___none_None; 400 } 401 402 __attr __fn_native__list_len(__attr __args[]) 403 { 404 __attr * const self = &__args[1]; 405 /* self.__data__ interpreted as fragment */ 406 unsigned int size = __load_via_object(self->value, __pos___data__).data->size; 407 408 /* Return the new integer. */ 409 return __new_int(size); 410 } 411 412 __attr __fn_native__list_nonempty(__attr __args[]) 413 { 414 __attr * const self = &__args[1]; 415 416 return __load_via_object(self->value, __pos___data__).data->size ? __builtins___boolean_True : __builtins___boolean_False; 417 } 418 419 __attr __fn_native__list_element(__attr __args[]) 420 { 421 __attr * const self = &__args[1]; 422 __attr * const index = &__args[2]; 423 /* self.__data__ interpreted as fragment */ 424 __attr *elements = __load_via_object(self->value, __pos___data__).data->attrs; 425 /* index.__data__ interpreted as int */ 426 int i = __load_via_object(index->value, __pos___data__).intvalue; 427 428 return elements[i]; 429 } 430 431 __attr __fn_native__list_to_tuple(__attr __args[]) 432 { 433 __attr * const l = &__args[1]; 434 435 /* NOTE: To be written. */ 436 return __builtins___none_None; 437 } 438 439 __attr __fn_native__buffer_str(__attr __args[]) 440 { 441 __attr * const self = &__args[1]; 442 /* self.__data__ interpreted as buffer */ 443 __fragment *data = __load_via_object(self->value, __pos___data__).data; 444 unsigned int size = 0, i, j, n; 445 char *s, *o; 446 447 /* Calculate the size of the string. */ 448 for (i = 0; i < data->size; i++) 449 size += strlen(data->attrs[i].strvalue); 450 451 /* Reserve space for a new string. */ 452 s = calloc(size + 1, sizeof(char)); 453 454 /* Build a single string from the buffer contents. */ 455 for (i = 0, j = 0; i < data->size; i++) 456 { 457 o = __load_via_object(data->attrs[i].value, __pos___data__).strvalue; 458 n = strlen(o); 459 strncpy(s + j, o, n); 460 j += n; 461 } 462 463 /* Return a new string. */ 464 return __new_str(s); 465 } 466 467 __attr __fn_native__tuple_init(__attr __args[]) 468 { 469 __attr * const size = &__args[1]; 470 /* size.__data__ interpreted as fragment */ 471 __fragment *data = calloc(__load_via_object(size->value, __pos___data__).intvalue, sizeof(__attr)); 472 __attr attr = {0, .data=data}; 473 474 return attr; 475 } 476 477 __attr __fn_native__tuple_len(__attr __args[]) 478 { 479 __attr * const self = &__args[1]; 480 /* self.__data__ interpreted as fragment */ 481 unsigned int size = __load_via_object(self->value, __pos___data__).data->size; 482 483 /* Return the new integer. */ 484 return __new_int(size); 485 } 486 487 __attr __fn_native__tuple_element(__attr __args[]) 488 { 489 __attr * const self = &__args[1]; 490 __attr * const index = &__args[2]; 491 /* self.__data__ interpreted as fragment */ 492 __attr *elements = __load_via_object(self->value, __pos___data__).data->attrs; 493 /* index.__data__ interpreted as int */ 494 int i = __load_via_object(index->value, __pos___data__).intvalue; 495 496 return elements[i]; 497 } 498 499 __attr __fn_native__isinstance(__attr __args[]) 500 { 501 __attr * const obj = &__args[1]; 502 __attr * const cls = &__args[2]; 503 504 if (__is_instance(obj->value) && __HASATTR(__get_class(obj->value), __TYPEPOS(cls->value), __TYPECODE(cls->value))) 505 return __builtins___boolean_True; 506 else 507 return __builtins___boolean_False; 508 } 509 510 __attr __fn_native__read(__attr __args[]) 511 { 512 __attr * const fd = &__args[1]; 513 __attr * const n = &__args[2]; 514 515 /* NOTE: To be written. */ 516 return __builtins___none_None; 517 } 518 519 __attr __fn_native__write(__attr __args[]) 520 { 521 __attr * const fd = &__args[1]; 522 __attr * const str = &__args[2]; 523 /* fd.__data__ interpreted as int */ 524 int i = __load_via_object(fd->value, __pos___data__).intvalue; 525 /* str.__data__ interpreted as string */ 526 char *s = __load_via_object(str->value, __pos___data__).strvalue; 527 528 write(i, s, sizeof(char) * strlen(s)); 529 return __builtins___none_None; 530 } 531 532 /* Module initialisation. */ 533 534 void __main_native() 535 { 536 }