xbintsc 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -9
- package/dist/src/codegen/llvm.js +422 -44
- package/dist/src/codegen/llvm.js.map +1 -1
- package/dist/src/parser/parser.js +4 -0
- package/dist/src/parser/parser.js.map +1 -1
- package/dist/tests/e2e/compile.test.js +122 -2
- package/dist/tests/e2e/compile.test.js.map +1 -1
- package/dist/tests/parser/parser.test.js +9 -1
- package/dist/tests/parser/parser.test.js.map +1 -1
- package/package.json +1 -1
- package/runtime/rt.h +32 -0
- package/runtime/xt_runtime.c +696 -6
- package/src/codegen/llvm.ts +458 -43
- package/src/parser/parser.ts +4 -0
package/runtime/xt_runtime.c
CHANGED
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
#include "rt.h"
|
|
19
19
|
|
|
20
|
+
#include <ctype.h>
|
|
20
21
|
#include <math.h>
|
|
22
|
+
#include <setjmp.h>
|
|
21
23
|
#include <stdio.h>
|
|
22
24
|
#include <stdlib.h>
|
|
23
25
|
#include <string.h>
|
|
@@ -438,13 +440,33 @@ xt_value xt_object_has(xt_value value, xt_value key) {
|
|
|
438
440
|
}
|
|
439
441
|
|
|
440
442
|
xt_value xt_object_keys(xt_value value) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
443
|
+
xt_value result = xt_array_new(0, NULL);
|
|
444
|
+
if (XT_IS_OBJECT(value)) {
|
|
445
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
446
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
447
|
+
xt_array_push(result, XT_FROM_PTR(XT_TAG_STRING, obj->properties[i].key));
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
446
450
|
}
|
|
447
|
-
|
|
451
|
+
if (XT_IS_ARRAY(value)) {
|
|
452
|
+
xt_array *array = (xt_array *)XT_GET_PTR(value);
|
|
453
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
454
|
+
char buffer[32];
|
|
455
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
456
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
457
|
+
}
|
|
458
|
+
return result;
|
|
459
|
+
}
|
|
460
|
+
if (XT_IS_STRING(value)) {
|
|
461
|
+
xt_string *s = xt_as_string(value);
|
|
462
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
463
|
+
char buffer[32];
|
|
464
|
+
snprintf(buffer, sizeof(buffer), "%u", i);
|
|
465
|
+
xt_array_push(result, xt_string_from_cstr(buffer));
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
448
470
|
}
|
|
449
471
|
|
|
450
472
|
/* Convenience used by codegen for `obj.prop`. */
|
|
@@ -526,6 +548,625 @@ xt_value xt_array_spread(xt_value target, xt_value source) {
|
|
|
526
548
|
return target;
|
|
527
549
|
}
|
|
528
550
|
|
|
551
|
+
/* ------------------------------------------------------------------------- */
|
|
552
|
+
/* Standard library: Array / String methods */
|
|
553
|
+
/* ------------------------------------------------------------------------- */
|
|
554
|
+
|
|
555
|
+
static xt_value xt_arg_at(int32_t argc, xt_value *argv, int32_t index) {
|
|
556
|
+
if (!argv || index < 0 || index >= argc) return XT_UNDEFINED;
|
|
557
|
+
return argv[index];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
static int xt_same_value_zero(xt_value a, xt_value b) {
|
|
561
|
+
if (XT_IS_NUMBER(a) && XT_IS_NUMBER(b)) {
|
|
562
|
+
double x = xt_to_double(a);
|
|
563
|
+
double y = xt_to_double(b);
|
|
564
|
+
if (isnan(x) && isnan(y)) return 1;
|
|
565
|
+
return x == y;
|
|
566
|
+
}
|
|
567
|
+
return xt_truthy(xt_seq(a, b));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
static xt_array *xt_as_array(xt_value value) {
|
|
571
|
+
if (XT_IS_ARRAY(value)) return (xt_array *)XT_GET_PTR(value);
|
|
572
|
+
return NULL;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/* -- array methods -------------------------------------------------------- */
|
|
576
|
+
|
|
577
|
+
static xt_value xt_array_pop(xt_value value) {
|
|
578
|
+
xt_array *array = xt_as_array(value);
|
|
579
|
+
if (!array || array->length == 0) return XT_UNDEFINED;
|
|
580
|
+
return array->items[--array->length];
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
static xt_value xt_array_shift(xt_value value) {
|
|
584
|
+
xt_array *array = xt_as_array(value);
|
|
585
|
+
if (!array || array->length == 0) return XT_UNDEFINED;
|
|
586
|
+
xt_value first = array->items[0];
|
|
587
|
+
for (uint32_t i = 1; i < array->length; i++) array->items[i - 1] = array->items[i];
|
|
588
|
+
array->length--;
|
|
589
|
+
return first;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
static xt_value xt_array_unshift(xt_value value, int32_t argc, xt_value *argv) {
|
|
593
|
+
xt_array *array = xt_as_array(value);
|
|
594
|
+
if (!array) return XT_UNDEFINED;
|
|
595
|
+
if (argc <= 0) return xt_number((double)array->length);
|
|
596
|
+
xt_array_reserve(array, array->length + (uint32_t)argc);
|
|
597
|
+
for (uint32_t i = array->length; i-- > 0;) array->items[i + argc] = array->items[i];
|
|
598
|
+
for (int32_t i = 0; i < argc; i++) array->items[i] = argv[i];
|
|
599
|
+
array->length += (uint32_t)argc;
|
|
600
|
+
return xt_number((double)array->length);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
static void xt_buffer_append(char **out, size_t *length, size_t *capacity, const char *data, size_t size) {
|
|
604
|
+
if (*length + size + 1 > *capacity) {
|
|
605
|
+
while (*length + size + 1 > *capacity) *capacity = (*capacity) * 2;
|
|
606
|
+
*out = (char *)realloc(*out, *capacity);
|
|
607
|
+
if (!*out) abort();
|
|
608
|
+
}
|
|
609
|
+
memcpy(*out + *length, data, size);
|
|
610
|
+
*length += size;
|
|
611
|
+
(*out)[*length] = '\0';
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
static xt_value xt_array_join(xt_value value, xt_value separator) {
|
|
615
|
+
xt_array *array = xt_as_array(value);
|
|
616
|
+
if (!array) return xt_string_from_cstr("");
|
|
617
|
+
xt_string *sep = xt_as_string(xt_to_string(separator == XT_UNDEFINED ? xt_string_from_cstr(",") : separator));
|
|
618
|
+
size_t capacity = 32;
|
|
619
|
+
size_t length = 0;
|
|
620
|
+
char *out = (char *)malloc(capacity);
|
|
621
|
+
if (!out) abort();
|
|
622
|
+
out[0] = '\0';
|
|
623
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
624
|
+
if (i > 0) xt_buffer_append(&out, &length, &capacity, sep->data, sep->length);
|
|
625
|
+
xt_value item = array->items[i];
|
|
626
|
+
if (item == XT_UNDEFINED || item == XT_NULL) continue;
|
|
627
|
+
xt_string *str = xt_as_string(xt_to_string(item));
|
|
628
|
+
xt_buffer_append(&out, &length, &capacity, str->data, str->length);
|
|
629
|
+
}
|
|
630
|
+
xt_value result = xt_string_new(out, length);
|
|
631
|
+
free(out);
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
static void xt_normalize_slice(int32_t len, int32_t *start, int32_t *end) {
|
|
636
|
+
if (*start < 0) *start += len;
|
|
637
|
+
if (*start < 0) *start = 0;
|
|
638
|
+
if (*start > len) *start = len;
|
|
639
|
+
if (*end < 0) *end += len;
|
|
640
|
+
if (*end < 0) *end = 0;
|
|
641
|
+
if (*end > len) *end = len;
|
|
642
|
+
if (*end < *start) *end = *start;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
static xt_value xt_array_slice(xt_value value, xt_value startValue, xt_value endValue) {
|
|
646
|
+
xt_array *array = xt_as_array(value);
|
|
647
|
+
if (!array) return XT_UNDEFINED;
|
|
648
|
+
int32_t len = (int32_t)array->length;
|
|
649
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
650
|
+
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
651
|
+
xt_normalize_slice(len, &start, &end);
|
|
652
|
+
return xt_array_new(end - start, array->items + start);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
static xt_value xt_array_index_of(xt_value value, xt_value needle, xt_value fromValue, int sameValueZero) {
|
|
656
|
+
xt_array *array = xt_as_array(value);
|
|
657
|
+
if (!array) return xt_number(-1);
|
|
658
|
+
int32_t from = fromValue == XT_UNDEFINED ? 0 : xt_to_int32(fromValue);
|
|
659
|
+
if (from < 0) from += (int32_t)array->length;
|
|
660
|
+
if (from < 0) from = 0;
|
|
661
|
+
for (uint32_t i = (uint32_t)from; i < array->length; i++) {
|
|
662
|
+
int equal = sameValueZero ? xt_same_value_zero(array->items[i], needle) : xt_truthy(xt_seq(array->items[i], needle));
|
|
663
|
+
if (equal) return xt_number((double)i);
|
|
664
|
+
}
|
|
665
|
+
return xt_number(-1);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
static xt_value xt_array_concat(xt_value value, int32_t argc, xt_value *argv) {
|
|
669
|
+
xt_array *array = xt_as_array(value);
|
|
670
|
+
xt_value result = xt_array_new(0, NULL);
|
|
671
|
+
if (!array) return result;
|
|
672
|
+
for (uint32_t i = 0; i < array->length; i++) xt_array_push(result, array->items[i]);
|
|
673
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
674
|
+
if (XT_IS_ARRAY(argv[i])) {
|
|
675
|
+
xt_array *other = xt_as_array(argv[i]);
|
|
676
|
+
for (uint32_t j = 0; j < other->length; j++) xt_array_push(result, other->items[j]);
|
|
677
|
+
} else {
|
|
678
|
+
xt_array_push(result, argv[i]);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
static xt_value xt_array_for_each(xt_value value, xt_value fn) {
|
|
685
|
+
xt_array *array = xt_as_array(value);
|
|
686
|
+
if (!array) return XT_UNDEFINED;
|
|
687
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
688
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
689
|
+
xt_closure_call(fn, 3, args);
|
|
690
|
+
}
|
|
691
|
+
return XT_UNDEFINED;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
static xt_value xt_array_map(xt_value value, xt_value fn) {
|
|
695
|
+
xt_array *array = xt_as_array(value);
|
|
696
|
+
xt_value result = xt_array_new(0, NULL);
|
|
697
|
+
if (!array) return result;
|
|
698
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
699
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
700
|
+
xt_array_push(result, xt_closure_call(fn, 3, args));
|
|
701
|
+
}
|
|
702
|
+
return result;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
static xt_value xt_array_filter(xt_value value, xt_value fn) {
|
|
706
|
+
xt_array *array = xt_as_array(value);
|
|
707
|
+
xt_value result = xt_array_new(0, NULL);
|
|
708
|
+
if (!array) return result;
|
|
709
|
+
for (uint32_t i = 0; i < array->length; i++) {
|
|
710
|
+
xt_value args[3] = {array->items[i], xt_number((double)i), value};
|
|
711
|
+
if (xt_truthy(xt_closure_call(fn, 3, args))) xt_array_push(result, array->items[i]);
|
|
712
|
+
}
|
|
713
|
+
return result;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
static xt_value xt_array_reduce(xt_value value, xt_value fn, int32_t hasInitial, xt_value initial) {
|
|
717
|
+
xt_array *array = xt_as_array(value);
|
|
718
|
+
if (!array) return XT_UNDEFINED;
|
|
719
|
+
uint32_t i = 0;
|
|
720
|
+
xt_value accumulator;
|
|
721
|
+
if (hasInitial) {
|
|
722
|
+
accumulator = initial;
|
|
723
|
+
} else if (array->length > 0) {
|
|
724
|
+
accumulator = array->items[0];
|
|
725
|
+
i = 1;
|
|
726
|
+
} else {
|
|
727
|
+
xt_throw(xt_string_from_cstr("TypeError: Reduce of empty array with no initial value"));
|
|
728
|
+
return XT_UNDEFINED;
|
|
729
|
+
}
|
|
730
|
+
for (; i < array->length; i++) {
|
|
731
|
+
xt_value args[4] = {accumulator, array->items[i], xt_number((double)i), value};
|
|
732
|
+
accumulator = xt_closure_call(fn, 4, args);
|
|
733
|
+
}
|
|
734
|
+
return accumulator;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/* -- string methods ------------------------------------------------------- */
|
|
738
|
+
|
|
739
|
+
static int32_t xt_string_find(xt_string *haystack, xt_string *needle, int32_t from) {
|
|
740
|
+
if (from < 0) from = 0;
|
|
741
|
+
if ((uint32_t)from > haystack->length) return -1;
|
|
742
|
+
if (needle->length == 0) return from;
|
|
743
|
+
for (uint32_t i = (uint32_t)from; i + needle->length <= haystack->length; i++) {
|
|
744
|
+
if (memcmp(haystack->data + i, needle->data, needle->length) == 0) return (int32_t)i;
|
|
745
|
+
}
|
|
746
|
+
return -1;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
static xt_value xt_string_char_at(xt_value value, xt_value indexValue) {
|
|
750
|
+
xt_string *s = xt_as_string(value);
|
|
751
|
+
if (!s) return xt_string_from_cstr("");
|
|
752
|
+
int32_t index = xt_to_int32(indexValue);
|
|
753
|
+
if (index < 0 || (uint32_t)index >= s->length) return xt_string_from_cstr("");
|
|
754
|
+
return xt_string_new(s->data + index, 1);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
static xt_value xt_string_char_code_at(xt_value value, xt_value indexValue) {
|
|
758
|
+
xt_string *s = xt_as_string(value);
|
|
759
|
+
if (!s) return xt_number(NAN);
|
|
760
|
+
int32_t index = xt_to_int32(indexValue);
|
|
761
|
+
if (index < 0 || (uint32_t)index >= s->length) return xt_number(NAN);
|
|
762
|
+
return xt_number((double)(unsigned char)s->data[index]);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
static xt_value xt_string_index_of(xt_value value, xt_value needleValue, xt_value fromValue) {
|
|
766
|
+
xt_string *s = xt_as_string(value);
|
|
767
|
+
if (!s) return xt_number(-1);
|
|
768
|
+
xt_string *needle = xt_as_string(xt_to_string(needleValue));
|
|
769
|
+
int32_t from = fromValue == XT_UNDEFINED ? 0 : xt_to_int32(fromValue);
|
|
770
|
+
return xt_number((double)xt_string_find(s, needle, from));
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
static xt_value xt_string_slice(xt_value value, xt_value startValue, xt_value endValue) {
|
|
774
|
+
xt_string *s = xt_as_string(value);
|
|
775
|
+
if (!s) return xt_string_from_cstr("");
|
|
776
|
+
int32_t len = (int32_t)s->length;
|
|
777
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
778
|
+
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
779
|
+
xt_normalize_slice(len, &start, &end);
|
|
780
|
+
return xt_string_new(s->data + start, (size_t)(end - start));
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
static xt_value xt_string_substring(xt_value value, xt_value startValue, xt_value endValue) {
|
|
784
|
+
xt_string *s = xt_as_string(value);
|
|
785
|
+
if (!s) return xt_string_from_cstr("");
|
|
786
|
+
int32_t len = (int32_t)s->length;
|
|
787
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
788
|
+
int32_t end = endValue == XT_UNDEFINED ? len : xt_to_int32(endValue);
|
|
789
|
+
if (start < 0) start = 0;
|
|
790
|
+
if (start > len) start = len;
|
|
791
|
+
if (end < 0) end = 0;
|
|
792
|
+
if (end > len) end = len;
|
|
793
|
+
if (start > end) {
|
|
794
|
+
int32_t swap = start;
|
|
795
|
+
start = end;
|
|
796
|
+
end = swap;
|
|
797
|
+
}
|
|
798
|
+
return xt_string_new(s->data + start, (size_t)(end - start));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
static xt_value xt_string_substr(xt_value value, xt_value startValue, xt_value lengthValue) {
|
|
802
|
+
xt_string *s = xt_as_string(value);
|
|
803
|
+
if (!s) return xt_string_from_cstr("");
|
|
804
|
+
int32_t len = (int32_t)s->length;
|
|
805
|
+
int32_t start = startValue == XT_UNDEFINED ? 0 : xt_to_int32(startValue);
|
|
806
|
+
if (start < 0) start += len;
|
|
807
|
+
if (start < 0) start = 0;
|
|
808
|
+
if (start > len) start = len;
|
|
809
|
+
int32_t length = lengthValue == XT_UNDEFINED ? len - start : xt_to_int32(lengthValue);
|
|
810
|
+
if (length < 0) length = 0;
|
|
811
|
+
if (start + length > len) length = len - start;
|
|
812
|
+
return xt_string_new(s->data + start, (size_t)length);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
static xt_value xt_string_split(xt_value value, xt_value separatorValue) {
|
|
816
|
+
xt_value result = xt_array_new(0, NULL);
|
|
817
|
+
xt_string *s = xt_as_string(value);
|
|
818
|
+
if (!s) return result;
|
|
819
|
+
if (separatorValue == XT_UNDEFINED) {
|
|
820
|
+
xt_array_push(result, value);
|
|
821
|
+
return result;
|
|
822
|
+
}
|
|
823
|
+
xt_string *sep = xt_as_string(xt_to_string(separatorValue));
|
|
824
|
+
if (sep->length == 0) {
|
|
825
|
+
for (uint32_t i = 0; i < s->length; i++) xt_array_push(result, xt_string_new(s->data + i, 1));
|
|
826
|
+
return result;
|
|
827
|
+
}
|
|
828
|
+
uint32_t start = 0;
|
|
829
|
+
uint32_t i = 0;
|
|
830
|
+
while (i + sep->length <= s->length) {
|
|
831
|
+
if (memcmp(s->data + i, sep->data, sep->length) == 0) {
|
|
832
|
+
xt_array_push(result, xt_string_new(s->data + start, i - start));
|
|
833
|
+
i += sep->length;
|
|
834
|
+
start = i;
|
|
835
|
+
} else {
|
|
836
|
+
i++;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
xt_array_push(result, xt_string_new(s->data + start, s->length - start));
|
|
840
|
+
return result;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
static xt_value xt_string_case(xt_value value, int upper) {
|
|
844
|
+
xt_string *s = xt_as_string(value);
|
|
845
|
+
if (!s) return value;
|
|
846
|
+
xt_string *out = xt_string_alloc(s->length);
|
|
847
|
+
for (uint32_t i = 0; i < s->length; i++) {
|
|
848
|
+
unsigned char c = (unsigned char)s->data[i];
|
|
849
|
+
out->data[i] = (char)(upper ? toupper((int)c) : tolower((int)c));
|
|
850
|
+
}
|
|
851
|
+
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
static xt_value xt_string_trim(xt_value value) {
|
|
855
|
+
xt_string *s = xt_as_string(value);
|
|
856
|
+
if (!s) return value;
|
|
857
|
+
uint32_t start = 0;
|
|
858
|
+
uint32_t end = s->length;
|
|
859
|
+
while (start < end && isspace((unsigned char)s->data[start])) start++;
|
|
860
|
+
while (end > start && isspace((unsigned char)s->data[end - 1])) end--;
|
|
861
|
+
return xt_string_new(s->data + start, end - start);
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
static xt_value xt_string_replace(xt_value value, xt_value searchValue, xt_value replacementValue) {
|
|
865
|
+
xt_string *s = xt_as_string(value);
|
|
866
|
+
if (!s) return value;
|
|
867
|
+
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
868
|
+
xt_string *replacement = xt_as_string(xt_to_string(replacementValue));
|
|
869
|
+
int32_t at = xt_string_find(s, search, 0);
|
|
870
|
+
if (at < 0) return value;
|
|
871
|
+
size_t total = s->length - search->length + replacement->length;
|
|
872
|
+
xt_string *out = xt_string_alloc(total);
|
|
873
|
+
memcpy(out->data, s->data, (size_t)at);
|
|
874
|
+
memcpy(out->data + at, replacement->data, replacement->length);
|
|
875
|
+
memcpy(out->data + at + replacement->length, s->data + at + search->length,
|
|
876
|
+
s->length - (size_t)at - search->length);
|
|
877
|
+
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
static xt_value xt_string_repeat(xt_value value, xt_value countValue) {
|
|
881
|
+
xt_string *s = xt_as_string(value);
|
|
882
|
+
if (!s) return value;
|
|
883
|
+
int32_t count = xt_to_int32(countValue);
|
|
884
|
+
if (count < 0) {
|
|
885
|
+
xt_throw(xt_string_from_cstr("RangeError: Invalid count value"));
|
|
886
|
+
return XT_UNDEFINED;
|
|
887
|
+
}
|
|
888
|
+
xt_string *out = xt_string_alloc((size_t)s->length * (size_t)count);
|
|
889
|
+
for (int32_t i = 0; i < count; i++) memcpy(out->data + (size_t)i * s->length, s->data, s->length);
|
|
890
|
+
return XT_FROM_PTR(XT_TAG_STRING, out);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
static xt_value xt_string_starts_with(xt_value value, xt_value searchValue) {
|
|
894
|
+
xt_string *s = xt_as_string(value);
|
|
895
|
+
if (!s) return XT_FALSE;
|
|
896
|
+
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
897
|
+
if (search->length > s->length) return XT_FALSE;
|
|
898
|
+
return xt_bool(memcmp(s->data, search->data, search->length) == 0);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
static xt_value xt_string_ends_with(xt_value value, xt_value searchValue) {
|
|
902
|
+
xt_string *s = xt_as_string(value);
|
|
903
|
+
if (!s) return XT_FALSE;
|
|
904
|
+
xt_string *search = xt_as_string(xt_to_string(searchValue));
|
|
905
|
+
if (search->length > s->length) return XT_FALSE;
|
|
906
|
+
return xt_bool(memcmp(s->data + s->length - search->length, search->data, search->length) == 0);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
static xt_value xt_string_concat_args(xt_value value, int32_t argc, xt_value *argv) {
|
|
910
|
+
xt_value result = XT_IS_STRING(value) ? value : xt_to_string(value);
|
|
911
|
+
for (int32_t i = 0; i < argc; i++) result = xt_add(result, xt_to_string(argv[i]));
|
|
912
|
+
return result;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/* -- method dispatch ------------------------------------------------------ */
|
|
916
|
+
|
|
917
|
+
static xt_value xt_array_method(xt_value target, const char *method, int32_t argc, xt_value *argv) {
|
|
918
|
+
if (strcmp(method, "push") == 0) {
|
|
919
|
+
xt_value result = xt_number(0);
|
|
920
|
+
for (int32_t i = 0; i < argc; i++) result = xt_array_push(target, argv[i]);
|
|
921
|
+
if (argc == 0) result = xt_number((double)xt_as_array(target)->length);
|
|
922
|
+
return result;
|
|
923
|
+
}
|
|
924
|
+
if (strcmp(method, "pop") == 0) return xt_array_pop(target);
|
|
925
|
+
if (strcmp(method, "shift") == 0) return xt_array_shift(target);
|
|
926
|
+
if (strcmp(method, "unshift") == 0) return xt_array_unshift(target, argc, argv);
|
|
927
|
+
if (strcmp(method, "join") == 0) return xt_array_join(target, xt_arg_at(argc, argv, 0));
|
|
928
|
+
if (strcmp(method, "slice") == 0) return xt_array_slice(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
929
|
+
if (strcmp(method, "indexOf") == 0) return xt_array_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 0);
|
|
930
|
+
if (strcmp(method, "includes") == 0) return xt_bool(xt_truthy(xt_ne(xt_array_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1), 1), xt_number(-1))));
|
|
931
|
+
if (strcmp(method, "concat") == 0) return xt_array_concat(target, argc, argv);
|
|
932
|
+
if (strcmp(method, "forEach") == 0) return xt_array_for_each(target, xt_arg_at(argc, argv, 0));
|
|
933
|
+
if (strcmp(method, "map") == 0) return xt_array_map(target, xt_arg_at(argc, argv, 0));
|
|
934
|
+
if (strcmp(method, "filter") == 0) return xt_array_filter(target, xt_arg_at(argc, argv, 0));
|
|
935
|
+
if (strcmp(method, "reduce") == 0) {
|
|
936
|
+
int32_t hasInitial = argc >= 2 ? 1 : 0;
|
|
937
|
+
return xt_array_reduce(target, xt_arg_at(argc, argv, 0), hasInitial, xt_arg_at(argc, argv, 1));
|
|
938
|
+
}
|
|
939
|
+
if (strcmp(method, "reverse") == 0) {
|
|
940
|
+
xt_array *array = xt_as_array(target);
|
|
941
|
+
for (uint32_t i = 0; i + 1 < array->length; i++, array->length--) {
|
|
942
|
+
xt_value tmp = array->items[i];
|
|
943
|
+
array->items[i] = array->items[array->length - 1];
|
|
944
|
+
array->items[array->length - 1] = tmp;
|
|
945
|
+
}
|
|
946
|
+
return target;
|
|
947
|
+
}
|
|
948
|
+
return XT_UNDEFINED;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
static xt_value xt_string_method(xt_value target, const char *method, int32_t argc, xt_value *argv) {
|
|
952
|
+
if (strcmp(method, "charAt") == 0) return xt_string_char_at(target, xt_arg_at(argc, argv, 0));
|
|
953
|
+
if (strcmp(method, "charCodeAt") == 0) return xt_string_char_code_at(target, xt_arg_at(argc, argv, 0));
|
|
954
|
+
if (strcmp(method, "indexOf") == 0) return xt_string_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
955
|
+
if (strcmp(method, "includes") == 0) return xt_bool(xt_truthy(xt_ne(xt_string_index_of(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1)), xt_number(-1))));
|
|
956
|
+
if (strcmp(method, "slice") == 0) return xt_string_slice(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
957
|
+
if (strcmp(method, "substring") == 0) return xt_string_substring(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
958
|
+
if (strcmp(method, "substr") == 0) return xt_string_substr(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
959
|
+
if (strcmp(method, "split") == 0) return xt_string_split(target, xt_arg_at(argc, argv, 0));
|
|
960
|
+
if (strcmp(method, "toUpperCase") == 0) return xt_string_case(target, 1);
|
|
961
|
+
if (strcmp(method, "toLowerCase") == 0) return xt_string_case(target, 0);
|
|
962
|
+
if (strcmp(method, "trim") == 0) return xt_string_trim(target);
|
|
963
|
+
if (strcmp(method, "replace") == 0) return xt_string_replace(target, xt_arg_at(argc, argv, 0), xt_arg_at(argc, argv, 1));
|
|
964
|
+
if (strcmp(method, "repeat") == 0) return xt_string_repeat(target, xt_arg_at(argc, argv, 0));
|
|
965
|
+
if (strcmp(method, "startsWith") == 0) return xt_string_starts_with(target, xt_arg_at(argc, argv, 0));
|
|
966
|
+
if (strcmp(method, "endsWith") == 0) return xt_string_ends_with(target, xt_arg_at(argc, argv, 0));
|
|
967
|
+
if (strcmp(method, "concat") == 0) return xt_string_concat_args(target, argc, argv);
|
|
968
|
+
return XT_UNDEFINED;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
xt_value xt_call_method(xt_value target, xt_value name, int32_t argc, xt_value *argv) {
|
|
972
|
+
const char *method = xt_string_data(name);
|
|
973
|
+
if (!method) return XT_UNDEFINED;
|
|
974
|
+
if (XT_IS_OBJECT(target)) {
|
|
975
|
+
xt_value fn = xt_object_get(target, name);
|
|
976
|
+
if (XT_IS_FUNCTION(fn)) return xt_closure_call(fn, argc, argv);
|
|
977
|
+
}
|
|
978
|
+
if (XT_IS_ARRAY(target)) return xt_array_method(target, method, argc, argv);
|
|
979
|
+
if (XT_IS_STRING(target)) return xt_string_method(target, method, argc, argv);
|
|
980
|
+
return XT_UNDEFINED;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/* ------------------------------------------------------------------------- */
|
|
984
|
+
/* Math */
|
|
985
|
+
/* ------------------------------------------------------------------------- */
|
|
986
|
+
|
|
987
|
+
xt_value xt_math_call(xt_value name, int32_t argc, xt_value *argv) {
|
|
988
|
+
const char *fn = xt_string_data(name);
|
|
989
|
+
double a = xt_to_number(xt_arg_at(argc, argv, 0));
|
|
990
|
+
double b = xt_to_number(xt_arg_at(argc, argv, 1));
|
|
991
|
+
if (!fn) return xt_number(NAN);
|
|
992
|
+
if (strcmp(fn, "abs") == 0) return xt_number(fabs(a));
|
|
993
|
+
if (strcmp(fn, "floor") == 0) return xt_number(floor(a));
|
|
994
|
+
if (strcmp(fn, "ceil") == 0) return xt_number(ceil(a));
|
|
995
|
+
if (strcmp(fn, "round") == 0) return xt_number(floor(a + 0.5));
|
|
996
|
+
if (strcmp(fn, "trunc") == 0) return xt_number(trunc(a));
|
|
997
|
+
if (strcmp(fn, "sqrt") == 0) return xt_number(sqrt(a));
|
|
998
|
+
if (strcmp(fn, "cbrt") == 0) return xt_number(cbrt(a));
|
|
999
|
+
if (strcmp(fn, "pow") == 0) return xt_number(pow(a, b));
|
|
1000
|
+
if (strcmp(fn, "exp") == 0) return xt_number(exp(a));
|
|
1001
|
+
if (strcmp(fn, "log") == 0) return xt_number(log(a));
|
|
1002
|
+
if (strcmp(fn, "log2") == 0) return xt_number(log2(a));
|
|
1003
|
+
if (strcmp(fn, "log10") == 0) return xt_number(log10(a));
|
|
1004
|
+
if (strcmp(fn, "sin") == 0) return xt_number(sin(a));
|
|
1005
|
+
if (strcmp(fn, "cos") == 0) return xt_number(cos(a));
|
|
1006
|
+
if (strcmp(fn, "tan") == 0) return xt_number(tan(a));
|
|
1007
|
+
if (strcmp(fn, "asin") == 0) return xt_number(asin(a));
|
|
1008
|
+
if (strcmp(fn, "acos") == 0) return xt_number(acos(a));
|
|
1009
|
+
if (strcmp(fn, "atan") == 0) return xt_number(atan(a));
|
|
1010
|
+
if (strcmp(fn, "atan2") == 0) return xt_number(atan2(a, b));
|
|
1011
|
+
if (strcmp(fn, "hypot") == 0) return xt_number(hypot(a, b));
|
|
1012
|
+
if (strcmp(fn, "sign") == 0) {
|
|
1013
|
+
if (isnan(a)) return xt_number(NAN);
|
|
1014
|
+
return xt_number(a > 0 ? 1.0 : a < 0 ? -1.0 : a);
|
|
1015
|
+
}
|
|
1016
|
+
if (strcmp(fn, "random") == 0) return xt_number((double)rand() / ((double)RAND_MAX + 1.0));
|
|
1017
|
+
if (strcmp(fn, "min") == 0) {
|
|
1018
|
+
double result = INFINITY;
|
|
1019
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
1020
|
+
double v = xt_to_number(argv[i]);
|
|
1021
|
+
if (isnan(v)) return xt_number(NAN);
|
|
1022
|
+
if (v < result) result = v;
|
|
1023
|
+
}
|
|
1024
|
+
return xt_number(result);
|
|
1025
|
+
}
|
|
1026
|
+
if (strcmp(fn, "max") == 0) {
|
|
1027
|
+
double result = -INFINITY;
|
|
1028
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
1029
|
+
double v = xt_to_number(argv[i]);
|
|
1030
|
+
if (isnan(v)) return xt_number(NAN);
|
|
1031
|
+
if (v > result) result = v;
|
|
1032
|
+
}
|
|
1033
|
+
return xt_number(result);
|
|
1034
|
+
}
|
|
1035
|
+
return xt_number(NAN);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/* ------------------------------------------------------------------------- */
|
|
1039
|
+
/* Object methods and global functions */
|
|
1040
|
+
/* ------------------------------------------------------------------------- */
|
|
1041
|
+
|
|
1042
|
+
xt_value xt_object_values(xt_value value) {
|
|
1043
|
+
xt_value result = xt_array_new(0, NULL);
|
|
1044
|
+
if (!XT_IS_OBJECT(value)) return result;
|
|
1045
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
1046
|
+
for (uint32_t i = 0; i < obj->count; i++) xt_array_push(result, obj->properties[i].value);
|
|
1047
|
+
return result;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
xt_value xt_object_entries(xt_value value) {
|
|
1051
|
+
xt_value result = xt_array_new(0, NULL);
|
|
1052
|
+
if (!XT_IS_OBJECT(value)) return result;
|
|
1053
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
1054
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
1055
|
+
xt_value pair = xt_array_new(0, NULL);
|
|
1056
|
+
xt_array_push(pair, XT_FROM_PTR(XT_TAG_STRING, obj->properties[i].key));
|
|
1057
|
+
xt_array_push(pair, obj->properties[i].value);
|
|
1058
|
+
xt_array_push(result, pair);
|
|
1059
|
+
}
|
|
1060
|
+
return result;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
xt_value xt_object_assign(int32_t argc, xt_value *argv) {
|
|
1064
|
+
if (argc <= 0) return xt_undefined();
|
|
1065
|
+
xt_value target = argv[0];
|
|
1066
|
+
if (!XT_IS_OBJECT(target)) return target;
|
|
1067
|
+
for (int32_t i = 1; i < argc; i++) {
|
|
1068
|
+
if (!XT_IS_OBJECT(argv[i])) continue;
|
|
1069
|
+
xt_object *source = (xt_object *)XT_GET_PTR(argv[i]);
|
|
1070
|
+
for (uint32_t j = 0; j < source->count; j++) {
|
|
1071
|
+
xt_object_set(target, XT_FROM_PTR(XT_TAG_STRING, source->properties[j].key), source->properties[j].value);
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return target;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
/* Copy every own enumerable property of `source` onto `target` (`{...source}`). */
|
|
1078
|
+
xt_value xt_object_spread(xt_value target, xt_value source) {
|
|
1079
|
+
xt_value args[2];
|
|
1080
|
+
args[0] = target;
|
|
1081
|
+
args[1] = source;
|
|
1082
|
+
return xt_object_assign(2, args);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
xt_value xt_parse_int(int32_t argc, xt_value *argv) {
|
|
1086
|
+
xt_string *s = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
1087
|
+
int32_t radix = argc >= 2 ? xt_to_int32(argv[1]) : 0;
|
|
1088
|
+
char *end = NULL;
|
|
1089
|
+
long value = strtol(s->data, &end, radix);
|
|
1090
|
+
if (end == s->data) return xt_number(NAN);
|
|
1091
|
+
return xt_number((double)value);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
xt_value xt_parse_float(int32_t argc, xt_value *argv) {
|
|
1095
|
+
xt_string *s = xt_as_string(xt_to_string(xt_arg_at(argc, argv, 0)));
|
|
1096
|
+
char *end = NULL;
|
|
1097
|
+
double value = strtod(s->data, &end);
|
|
1098
|
+
if (end == s->data) return xt_number(NAN);
|
|
1099
|
+
return xt_number(value);
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
xt_value xt_is_nan(int32_t argc, xt_value *argv) {
|
|
1103
|
+
double value = xt_to_number(xt_arg_at(argc, argv, 0));
|
|
1104
|
+
return xt_bool(value != value);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
xt_value xt_is_finite(int32_t argc, xt_value *argv) {
|
|
1108
|
+
double value = xt_to_number(xt_arg_at(argc, argv, 0));
|
|
1109
|
+
return xt_bool(!isnan(value) && !isinf(value));
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
xt_value xt_number_ctor(int32_t argc, xt_value *argv) {
|
|
1113
|
+
if (argc == 0) return xt_number(0);
|
|
1114
|
+
return xt_number(xt_to_number(argv[0]));
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
xt_value xt_string_ctor(int32_t argc, xt_value *argv) {
|
|
1118
|
+
if (argc == 0) return xt_string_from_cstr("");
|
|
1119
|
+
return xt_to_string(argv[0]);
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
xt_value xt_boolean_ctor(int32_t argc, xt_value *argv) {
|
|
1123
|
+
if (argc == 0) return XT_FALSE;
|
|
1124
|
+
return xt_bool(xt_truthy(argv[0]));
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
xt_value xt_in(xt_value key, xt_value value) {
|
|
1128
|
+
if (XT_IS_OBJECT(value)) return xt_object_has(value, key);
|
|
1129
|
+
if (XT_IS_ARRAY(value)) {
|
|
1130
|
+
int32_t index = xt_to_int32(key);
|
|
1131
|
+
return xt_bool(index >= 0 && (uint32_t)index < xt_as_array(value)->length);
|
|
1132
|
+
}
|
|
1133
|
+
if (XT_IS_STRING(value)) {
|
|
1134
|
+
xt_string *s = xt_as_string(value);
|
|
1135
|
+
xt_string *k = xt_as_string(xt_to_string(key));
|
|
1136
|
+
if (k->length == 6 && memcmp(k->data, "length", 6) == 0) return XT_TRUE;
|
|
1137
|
+
int32_t index = xt_to_int32(key);
|
|
1138
|
+
return xt_bool(index >= 0 && (uint32_t)index < s->length);
|
|
1139
|
+
}
|
|
1140
|
+
return XT_FALSE;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
xt_value xt_delete(xt_value value, xt_value key) {
|
|
1144
|
+
if (XT_IS_OBJECT(value)) {
|
|
1145
|
+
xt_object *obj = (xt_object *)XT_GET_PTR(value);
|
|
1146
|
+
xt_string *k = xt_as_string(xt_to_string(key));
|
|
1147
|
+
for (uint32_t i = 0; i < obj->count; i++) {
|
|
1148
|
+
if (xt_string_equals(obj->properties[i].key, k)) {
|
|
1149
|
+
for (uint32_t j = i + 1; j < obj->count; j++) obj->properties[j - 1] = obj->properties[j];
|
|
1150
|
+
obj->count--;
|
|
1151
|
+
break;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
return XT_TRUE;
|
|
1155
|
+
}
|
|
1156
|
+
if (XT_IS_ARRAY(value)) {
|
|
1157
|
+
xt_array_set(value, key, XT_UNDEFINED);
|
|
1158
|
+
return XT_TRUE;
|
|
1159
|
+
}
|
|
1160
|
+
return XT_TRUE;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
xt_value xt_rest_args(int32_t argc, xt_value *argv, int32_t start) {
|
|
1164
|
+
if (start < 0) start = 0;
|
|
1165
|
+
int32_t count = argc - start;
|
|
1166
|
+
if (count < 0) count = 0;
|
|
1167
|
+
return xt_array_new(count, argv ? argv + start : NULL);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
529
1170
|
/* ------------------------------------------------------------------------- */
|
|
530
1171
|
/* Generic member access */
|
|
531
1172
|
/* ------------------------------------------------------------------------- */
|
|
@@ -615,7 +1256,44 @@ int32_t xt_closure_arity(xt_value value) {
|
|
|
615
1256
|
/* Exceptions and output */
|
|
616
1257
|
/* ------------------------------------------------------------------------- */
|
|
617
1258
|
|
|
1259
|
+
/*
|
|
1260
|
+
* `try`/`catch` is implemented with a stack of setjmp frames. The compiler
|
|
1261
|
+
* allocates a frame with `xt_try_enter`, calls `_setjmp` on it, and pops it
|
|
1262
|
+
* with `xt_try_leave`. `xt_throw` longjmps into the innermost frame when one
|
|
1263
|
+
* is active, and only prints + exits when the exception is uncaught.
|
|
1264
|
+
*/
|
|
1265
|
+
typedef struct xt_try_frame {
|
|
1266
|
+
jmp_buf buf;
|
|
1267
|
+
struct xt_try_frame *prev;
|
|
1268
|
+
xt_value exception;
|
|
1269
|
+
} xt_try_frame;
|
|
1270
|
+
|
|
1271
|
+
static xt_try_frame *g_try_top = NULL;
|
|
1272
|
+
|
|
1273
|
+
void *xt_try_enter(void) {
|
|
1274
|
+
xt_try_frame *frame = (xt_try_frame *)calloc(1, sizeof(xt_try_frame));
|
|
1275
|
+
if (!frame) abort();
|
|
1276
|
+
frame->prev = g_try_top;
|
|
1277
|
+
frame->exception = XT_UNDEFINED;
|
|
1278
|
+
g_try_top = frame;
|
|
1279
|
+
return (void *)frame;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
xt_value xt_try_exception(void *framePtr) {
|
|
1283
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
1284
|
+
return frame ? frame->exception : XT_UNDEFINED;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
void xt_try_leave(void *framePtr) {
|
|
1288
|
+
xt_try_frame *frame = (xt_try_frame *)framePtr;
|
|
1289
|
+
if (frame && g_try_top == frame) g_try_top = frame->prev;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
618
1292
|
void xt_throw(xt_value v) {
|
|
1293
|
+
if (g_try_top) {
|
|
1294
|
+
g_try_top->exception = v;
|
|
1295
|
+
_longjmp(g_try_top->buf, 1);
|
|
1296
|
+
}
|
|
619
1297
|
xt_value message = xt_to_string(v);
|
|
620
1298
|
xt_string *s = xt_as_string(message);
|
|
621
1299
|
fprintf(stderr, "Uncaught %s\n", s->data);
|
|
@@ -680,3 +1358,15 @@ void xt_console_log(int32_t argc, xt_value *argv) {
|
|
|
680
1358
|
}
|
|
681
1359
|
fputc('\n', stdout);
|
|
682
1360
|
}
|
|
1361
|
+
|
|
1362
|
+
static void xt_console_write(int32_t argc, xt_value *argv, FILE *out) {
|
|
1363
|
+
for (int32_t i = 0; i < argc; i++) {
|
|
1364
|
+
if (i > 0) fputc(' ', out);
|
|
1365
|
+
xt_inspect(argv[i], out);
|
|
1366
|
+
}
|
|
1367
|
+
fputc('\n', out);
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
void xt_console_info(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stdout); }
|
|
1371
|
+
void xt_console_warn(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|
|
1372
|
+
void xt_console_error(int32_t argc, xt_value *argv) { xt_console_write(argc, argv, stderr); }
|