Baremetal Lisp interpreter and compiler for low-resource devices
Revision | c57088232b60ef6f3c8c88a9d246d2987e01cd35 (tree) |
---|---|
Zeit | 2020-09-21 09:51:46 |
Autor | AlaskanEmily <emily@alas...> |
Commiter | AlaskanEmily |
Add some very basic typechecking for SL_I_Execute
@@ -508,6 +508,13 @@ static void sl_i_defproto(struct SL_I_Runtime *rt, | ||
508 | 508 | void *old; |
509 | 509 | sl_s_len_t num_methods, i, e; |
510 | 510 | |
511 | + /* Do not allow re-defining protocols. */ | |
512 | + for(i = 0; i < rt->num_protocols; i++){ | |
513 | + if(SL_S_COMPARE_ATOMS(rt->protocols[i].name, name)){ | |
514 | + rt->pending_error = "Duplicate name for defproto"; | |
515 | + return; | |
516 | + } | |
517 | + } | |
511 | 518 | num_methods = SL_S_Length(methods); |
512 | 519 | method_array = |
513 | 520 | SL_S_Malloc(num_methods * sizeof(struct SL_X_ProtocolMethod)); |
@@ -619,7 +626,7 @@ SL_S_FUNC(int) SL_I_Run(struct SL_I_Runtime *rt, const struct SL_S_List *code){ | ||
619 | 626 | sl_i_defproto(rt, name, body); |
620 | 627 | } |
621 | 628 | else{ |
622 | - SL_I_Execute(rt, code->head); | |
629 | + SL_I_Execute(rt, code->head, SL_S_NIL); | |
623 | 630 | } |
624 | 631 | } |
625 | 632 | if(rt->pending_error) |
@@ -636,12 +643,15 @@ static const unsigned char sl_i_if_flags[SL_I_IF_ARITY] = { | ||
636 | 643 | SL_S_OUT_ANY, |
637 | 644 | SL_S_OUT_ANY |
638 | 645 | }; |
639 | -static void *sl_i_if(struct SL_I_Runtime *rt, const struct SL_S_List *in){ | |
646 | +static void *sl_i_if(struct SL_I_Runtime *rt, | |
647 | + const struct SL_S_List *in, | |
648 | + const struct SL_S_Atom **opt_out_hint){ | |
649 | + | |
640 | 650 | const void *values[SL_I_IF_ARITY], *result; |
641 | 651 | struct SL_S_List rebuild; |
642 | 652 | register int i; |
643 | 653 | |
644 | - rebuild.head = SL_I_Execute(rt, in->head); | |
654 | + rebuild.head = SL_I_Execute(rt, in->head, SL_S_NIL); | |
645 | 655 | if(rt->pending_error) |
646 | 656 | return SL_S_NIL; |
647 | 657 |
@@ -668,8 +678,8 @@ static void *sl_i_if(struct SL_I_Runtime *rt, const struct SL_S_List *in){ | ||
668 | 678 | rt->pending_error = "First arg to if must be true or false."; |
669 | 679 | return SL_S_NIL; |
670 | 680 | } |
671 | - | |
672 | - result = SL_I_Execute(rt, (void*)result); | |
681 | + /* TODO: We should check the type hint of the un-evaluated side, too. */ | |
682 | + result = SL_I_Execute(rt, (void*)result, opt_out_hint); | |
673 | 683 | SL_S_INCREF(result); |
674 | 684 | return (void*)result; |
675 | 685 | } |
@@ -707,7 +717,7 @@ SL_S_FUNC(void) *sl_i_to_int(const void *value, void *arg){ | ||
707 | 717 | return (void*)value; |
708 | 718 | } |
709 | 719 | |
710 | - value = SL_I_Execute(data->rt, (void*)value); | |
720 | + value = SL_I_Execute(data->rt, (void*)value, SL_S_NIL); | |
711 | 721 | |
712 | 722 | if(SL_S_IS_ATOM(value) && |
713 | 723 | SL_X_IsInt(SL_S_PTR_FROM_TAG(value)) == 0){ |
@@ -810,10 +820,10 @@ static const void * sl_i_ ## NAME (struct SL_I_Runtime *rt, \ | ||
810 | 820 | rt->pending_error = "Wrong number of args in " #SYMBOL; \ |
811 | 821 | return SL_S_NIL; \ |
812 | 822 | } \ |
813 | - a = SL_I_Execute(rt, in->head); \ | |
823 | + a = SL_I_Execute(rt, in->head, SL_S_NIL); \ | |
814 | 824 | if(rt->pending_error) \ |
815 | 825 | return SL_S_NIL; \ |
816 | - b = SL_I_Execute(rt, in->tail->head); \ | |
826 | + b = SL_I_Execute(rt, in->tail->head, SL_S_NIL); \ | |
817 | 827 | if(rt->pending_error){ \ |
818 | 828 | SL_S_DECREF(a); \ |
819 | 829 | return SL_S_NIL; \ |
@@ -849,11 +859,11 @@ static void *sl_i_compare(struct SL_I_Runtime *rt, | ||
849 | 859 | |
850 | 860 | const void *exe_a, *exe_b; |
851 | 861 | int i; |
852 | - | |
853 | - exe_a = SL_I_Execute(rt, a); | |
862 | + | |
863 | + exe_a = SL_I_Execute(rt, a, SL_S_NIL); | |
854 | 864 | if(rt->pending_error) |
855 | 865 | return SL_S_NIL; |
856 | - exe_b = SL_I_Execute(rt, b); | |
866 | + exe_b = SL_I_Execute(rt, b, SL_S_NIL); | |
857 | 867 | if(rt->pending_error){ |
858 | 868 | SL_S_DECREF(exe_a); |
859 | 869 | return SL_S_NIL; |
@@ -867,24 +877,37 @@ static void *sl_i_compare(struct SL_I_Runtime *rt, | ||
867 | 877 | |
868 | 878 | /*****************************************************************************/ |
869 | 879 | |
870 | -SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value){ | |
880 | +SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, | |
881 | + const void *value, | |
882 | + const struct SL_S_Atom **opt_out_hint){ | |
883 | + | |
871 | 884 | struct SL_S_Atom *atom; |
872 | 885 | struct SL_S_List *list, *ret_list; |
873 | 886 | struct SL_X_MeasureResult measure_result; |
874 | 887 | struct SL_I_Frame *frame; |
875 | 888 | sl_s_len_t i; |
889 | + | |
890 | +#define SL_I_OUT_HINT(WHAT) do{ \ | |
891 | + if(opt_out_hint) \ | |
892 | + *opt_out_hint = (WHAT); \ | |
893 | +}while(0) | |
876 | 894 | |
877 | - if(SL_S_IS_NIL(value)) | |
895 | + if(SL_S_IS_NIL(value)){ | |
896 | + SL_I_OUT_HINT(SL_S_NIL); | |
878 | 897 | return SL_S_NIL; |
898 | + } | |
879 | 899 | if(SL_S_IS_ATOM(value)){ |
880 | 900 | atom = SL_S_PTR_FROM_TAG(value); |
881 | 901 | if(SL_S_COMPARE_ATOMS(&sl_x_nil, atom)){ |
902 | + SL_I_OUT_HINT(SL_S_NIL); | |
882 | 903 | return SL_S_NIL; |
883 | 904 | } |
884 | 905 | else if(SL_S_COMPARE_ATOMS(&sl_x_true, atom)){ |
906 | + SL_I_OUT_HINT(&sl_x_atom_hint); | |
885 | 907 | return SL_S_MK_ATOM(&sl_x_true); |
886 | 908 | } |
887 | 909 | else if(SL_S_COMPARE_ATOMS(&sl_x_false, atom)){ |
910 | + SL_I_OUT_HINT(&sl_x_atom_hint); | |
888 | 911 | return SL_S_MK_ATOM(&sl_x_false); |
889 | 912 | } |
890 | 913 | else{ |
@@ -895,16 +918,20 @@ SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value){ | ||
895 | 918 | if(SL_S_COMPARE_ATOMS(atom, frame->defs[i].name)){ |
896 | 919 | value = frame->defs[i].value; |
897 | 920 | SL_S_INCREF(value); |
898 | - return (void*)value;; | |
921 | + SL_S_INCREF(frame->defs[i].hint); | |
922 | + SL_I_OUT_HINT(frame->defs[i].hint); | |
923 | + return (void*)value; | |
899 | 924 | } |
900 | 925 | } |
901 | 926 | }while((frame = frame->next) != SL_S_NIL); |
902 | 927 | |
903 | 928 | SL_S_INCREF(value); |
929 | + SL_I_OUT_HINT(SL_S_NIL); | |
904 | 930 | return (void*)value; |
905 | 931 | } |
906 | 932 | } |
907 | 933 | else if(!SL_S_IS_LIST(value)){ |
934 | + SL_I_OUT_HINT(SL_S_NIL); | |
908 | 935 | SL_S_INCREF(value); |
909 | 936 | return (void*)value; |
910 | 937 | } |
@@ -919,8 +946,10 @@ SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value){ | ||
919 | 946 | atom = SL_S_PTR_FROM_TAG(list->head); |
920 | 947 | |
921 | 948 | /* Comment */ |
922 | - if(SL_S_COMPARE_ATOMS(&sl_x_comment, atom)) | |
949 | + if(SL_S_COMPARE_ATOMS(&sl_x_comment, atom)){ | |
950 | + SL_I_OUT_HINT(SL_S_NIL); | |
923 | 951 | return SL_S_NIL; |
952 | + } | |
924 | 953 | |
925 | 954 | /* Tick escape */ |
926 | 955 | if(!SL_S_IS_NIL(list->tail) && |
@@ -933,6 +962,7 @@ SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value){ | ||
933 | 962 | } |
934 | 963 | |
935 | 964 | SL_S_INCREF(list->tail->head); |
965 | + SL_I_OUT_HINT(SL_S_NIL); | |
936 | 966 | return list->tail->head; |
937 | 967 | } |
938 | 968 |
@@ -944,12 +974,13 @@ SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value){ | ||
944 | 974 | } |
945 | 975 | /* All this is safe for nil. */ |
946 | 976 | SL_S_INCREF(list->tail); |
977 | + SL_I_OUT_HINT(&sl_x_list_hint); | |
947 | 978 | return SL_S_MK_LIST(list->tail); |
948 | 979 | } |
949 | 980 | |
950 | 981 | /* if */ |
951 | 982 | if(SL_S_COMPARE_ATOMS(&sl_x_if, atom)){ |
952 | - return sl_i_if(rt, list->tail); | |
983 | + return sl_i_if(rt, list->tail, opt_out_hint); | |
953 | 984 | } |
954 | 985 | |
955 | 986 | #define SL_I_TEST_ARITHMETIC(NAME, SYMBOL) \ |
@@ -966,10 +997,12 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
966 | 997 | rt->pending_error = "Invalid arity in " #NAME "?"; \ |
967 | 998 | return SL_S_NIL; \ |
968 | 999 | } \ |
969 | - value = SL_I_Execute(rt, list->tail->head); \ | |
1000 | + value = SL_I_Execute(rt, list->tail->head, SL_S_NIL); \ | |
970 | 1001 | if(rt->pending_error) \ |
971 | 1002 | return SL_S_NIL; \ |
1003 | + SL_I_OUT_HINT(&sl_x_atom_hint); \ | |
972 | 1004 | if(TESTER(value)){ \ |
1005 | + SL_S_DECREF(value); \ | |
973 | 1006 | return SL_S_MK_ATOM(&sl_x_true); \ |
974 | 1007 | } \ |
975 | 1008 | else{ \ |
@@ -982,6 +1015,7 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
982 | 1015 | SL_I_TEST(list, SL_S_IS_LIST) |
983 | 1016 | #define SL_I_TEST_INT(X) \ |
984 | 1017 | (SL_S_IS_ATOM(X) && SL_X_IsInt(SL_S_PTR_FROM_TAG(X)) == 0) |
1018 | + | |
985 | 1019 | SL_I_TEST(int, SL_I_TEST_INT) |
986 | 1020 | |
987 | 1021 | #undef SL_I_TEST_INT |
@@ -1009,7 +1043,9 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1009 | 1043 | SL_S_ForEach(SL_X_ConcatAtomsCB, ret_list, atom); |
1010 | 1044 | atom->text[measure_result.len] = '\0'; |
1011 | 1045 | SL_S_DECREF(ret_list); |
1012 | - return atom; | |
1046 | + | |
1047 | + SL_I_OUT_HINT(&sl_x_atom_hint); | |
1048 | + return SL_S_MK_ATOM(atom); | |
1013 | 1049 | } |
1014 | 1050 | |
1015 | 1051 | /* cons */ |
@@ -1018,7 +1054,7 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1018 | 1054 | rt->pending_error = "Invalid arity in cons."; |
1019 | 1055 | return SL_S_NIL; |
1020 | 1056 | } |
1021 | - value = SL_I_Execute(rt, list->tail->tail->head); | |
1057 | + value = SL_I_Execute(rt, list->tail->tail->head, SL_S_NIL); | |
1022 | 1058 | if(rt->pending_error) |
1023 | 1059 | return SL_S_NIL; |
1024 | 1060 | if(!SL_S_IS_LIST(value)){ |
@@ -1028,22 +1064,23 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1028 | 1064 | } |
1029 | 1065 | ret_list = SL_S_Malloc(sizeof(struct SL_S_List)); |
1030 | 1066 | ret_list->ref = 1; |
1031 | - ret_list->head = SL_I_Execute(rt, list->tail->head); | |
1067 | + ret_list->head = SL_I_Execute(rt, list->tail->head, SL_S_NIL); | |
1032 | 1068 | ret_list->tail = SL_S_PTR_FROM_TAG(value); |
1033 | 1069 | if(rt->pending_error){ |
1034 | 1070 | SL_S_FREE_LIST(ret_list); |
1035 | 1071 | return SL_S_NIL; |
1036 | 1072 | } |
1037 | - return ret_list; | |
1073 | + SL_I_OUT_HINT(&sl_x_list_hint); | |
1074 | + return SL_S_MK_LIST(ret_list); | |
1038 | 1075 | } |
1039 | 1076 | |
1040 | 1077 | /* head */ |
1041 | 1078 | if(SL_S_COMPARE_ATOMS(&sl_x_head, atom)){ |
1042 | - if(SL_S_LengthCompare(list->tail, 2) != 0){ | |
1079 | + if(SL_S_LengthCompare(list->tail, 1) != 0){ | |
1043 | 1080 | rt->pending_error = "Invalid arity in head."; |
1044 | 1081 | return SL_S_NIL; |
1045 | 1082 | } |
1046 | - value = SL_I_Execute(rt, list->tail->head); | |
1083 | + value = SL_I_Execute(rt, list->tail->head, SL_S_NIL); | |
1047 | 1084 | if(rt->pending_error) |
1048 | 1085 | return SL_S_NIL; |
1049 | 1086 | if(!SL_S_IS_LIST(value)){ |
@@ -1055,27 +1092,19 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1055 | 1092 | value = ret_list->head; |
1056 | 1093 | SL_S_INCREF(value); |
1057 | 1094 | SL_S_DECREF(ret_list); |
1095 | + SL_I_OUT_HINT(SL_S_NIL); | |
1058 | 1096 | return (void*)value; |
1059 | 1097 | } |
1060 | 1098 | |
1061 | - /* head */ | |
1099 | + /* tail */ | |
1062 | 1100 | if(SL_S_COMPARE_ATOMS(&sl_x_tail, atom)){ |
1063 | - if(SL_S_LengthCompare(list->tail, 2) != 0){ | |
1101 | + if(SL_S_LengthCompare(list->tail, 1) != 0){ | |
1064 | 1102 | rt->pending_error = "Invalid arity in tail."; |
1065 | 1103 | return SL_S_NIL; |
1066 | 1104 | } |
1067 | - value = SL_I_Execute(rt, list->tail->head); | |
1068 | - if(rt->pending_error) | |
1069 | - return SL_S_NIL; | |
1070 | - if(!SL_S_IS_LIST(value)){ | |
1071 | - SL_S_DECREF(value); | |
1072 | - rt->pending_error = "Invalid arguments to tail."; | |
1073 | - return SL_S_NIL; | |
1074 | - } | |
1075 | - ret_list = SL_S_PTR_FROM_TAG(value); | |
1076 | - value = SL_S_MK_LIST(ret_list->tail); | |
1105 | + value = SL_S_MK_LIST(list->tail->tail); | |
1077 | 1106 | SL_S_INCREF(value); |
1078 | - SL_S_DECREF(ret_list); | |
1107 | + SL_I_OUT_HINT(&sl_x_list_hint); | |
1079 | 1108 | return (void*)value; |
1080 | 1109 | } |
1081 | 1110 |
@@ -1085,9 +1114,10 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1085 | 1114 | rt->pending_error = "Invalid arity in not."; |
1086 | 1115 | return SL_S_NIL; |
1087 | 1116 | } |
1088 | - value = SL_I_Execute(rt, list->tail->head); | |
1117 | + value = SL_I_Execute(rt, list->tail->head, SL_S_NIL); | |
1089 | 1118 | if(rt->pending_error) |
1090 | 1119 | return SL_S_NIL; |
1120 | + SL_I_OUT_HINT(&sl_x_atom_hint); | |
1091 | 1121 | /* Very minor optimization, check for address equivalence with |
1092 | 1122 | * the boolean primitives */ |
1093 | 1123 | if(SL_S_PTR_FROM_TAG(value) == &sl_x_true){ |
@@ -1124,6 +1154,7 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1124 | 1154 | rt->pending_error = "Invalid arith in ="; |
1125 | 1155 | return SL_S_NIL; |
1126 | 1156 | } |
1157 | + SL_I_OUT_HINT(&sl_x_atom_hint); | |
1127 | 1158 | return sl_i_compare(rt, |
1128 | 1159 | list->tail->head, |
1129 | 1160 | list->tail->tail->head); |
@@ -1135,6 +1166,8 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1135 | 1166 | if(SL_S_LengthCompare(list->tail, |
1136 | 1167 | rt->binds[i].arity) == 0){ |
1137 | 1168 | |
1169 | + SL_S_INCREF(rt->binds[i].hint); | |
1170 | + SL_I_OUT_HINT(rt->binds[i].hint); | |
1138 | 1171 | return SL_I_Call(rt, rt->binds + i, list->tail); |
1139 | 1172 | } |
1140 | 1173 | else{ |
@@ -1170,7 +1203,7 @@ SL_I_ALL_ARITHMETIC(SL_I_TEST_ARITHMETIC) | ||
1170 | 1203 | SL_S_FUNC(void) *SL_I_Execute2(const void *value, void *rt){ |
1171 | 1204 | if(((struct SL_I_Runtime*)rt)->pending_error) |
1172 | 1205 | return SL_S_NIL; |
1173 | - return SL_I_Execute(rt, (void*)value); | |
1206 | + return SL_I_Execute(rt, (void*)value, SL_S_NIL); | |
1174 | 1207 | } |
1175 | 1208 | |
1176 | 1209 | /*****************************************************************************/ |
@@ -1200,7 +1233,8 @@ SL_S_FUNC(void) *SL_I_Call(struct SL_I_Runtime *rt, | ||
1200 | 1233 | frame.num_defs = frame.cap_defs = bind->arity; |
1201 | 1234 | for(i = 0; i < bind->arity; i++){ |
1202 | 1235 | frame.defs[i].name = bind->args[i].name; |
1203 | - value = SL_I_Execute(rt, args->head); | |
1236 | + /* TODO: Use the output hint from SL_I_Execute! */ | |
1237 | + value = SL_I_Execute(rt, args->head, SL_S_NIL); | |
1204 | 1238 | hint = bind->args[i].hint; |
1205 | 1239 | if(!(SL_S_IS_NIL(hint) || SL_S_COMPARE_ATOMS(hint, &sl_x_nil))){ |
1206 | 1240 | /* Validate the type. */ |
@@ -1312,7 +1346,8 @@ type_hint_done: | ||
1312 | 1346 | code = code->tail){ |
1313 | 1347 | |
1314 | 1348 | SL_S_DECREF(value); |
1315 | - value = SL_I_Execute(rt, code->head); | |
1349 | + /* TODO: Check that the final value matches our output hint! */ | |
1350 | + value = SL_I_Execute(rt, code->head, SL_S_NIL); | |
1316 | 1351 | } |
1317 | 1352 | |
1318 | 1353 | /* Clean up the stack. */ |
@@ -41,6 +41,7 @@ struct SL_I_Runtime; | ||
41 | 41 | |
42 | 42 | struct SL_I_Bind{ |
43 | 43 | const struct SL_S_Atom *name; |
44 | + const struct SL_S_Atom *hint; | |
44 | 45 | union { |
45 | 46 | SL_S_FUNC_PTR(void*, native)( |
46 | 47 | struct SL_I_Runtime *rt, |
@@ -48,7 +49,7 @@ struct SL_I_Bind{ | ||
48 | 49 | const struct SL_S_List *lisp; |
49 | 50 | } bind; |
50 | 51 | sl_s_len_t arity; |
51 | - struct SL_X_FuncArg *args; /* Unused (for now) on native binds. */ | |
52 | + struct SL_X_FuncArg *args; | |
52 | 53 | unsigned char is_native; |
53 | 54 | }; |
54 | 55 |
@@ -93,8 +94,13 @@ SL_S_FUNC(void) SL_I_InitRuntime(struct SL_I_Runtime *rt); | ||
93 | 94 | SL_S_FUNC(int) SL_I_Run(struct SL_I_Runtime *rt, const struct SL_S_List *code); |
94 | 95 | |
95 | 96 | /*****************************************************************************/ |
96 | -/* The result must be DECREF'ed */ | |
97 | -SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, const void *value); | |
97 | +/* The result must be DECREF'ed. | |
98 | + * If opt_out_hint is not SL_S_NIL, then the return-type hint (if one exists) | |
99 | + * will be placed into the destination. | |
100 | + */ | |
101 | +SL_S_FUNC(void) *SL_I_Execute(struct SL_I_Runtime *rt, | |
102 | + const void *value, | |
103 | + const struct SL_S_Atom **opt_out_hint); | |
98 | 104 | |
99 | 105 | /*****************************************************************************/ |
100 | 106 | /* Args reversed form of SL_I_Execute. */ |
@@ -103,6 +103,24 @@ SL_X_ATOM(sl_x_le, "<="); | ||
103 | 103 | |
104 | 104 | /*****************************************************************************/ |
105 | 105 | |
106 | +const struct SL_S_Atom *const sl_x_all_hints[] = { | |
107 | + &sl_x_list_hint, | |
108 | + &sl_x_atom_hint, | |
109 | + | |
110 | +#define SL_X_HINT_REF(X) &(sl_x_ ## X ## _hint), | |
111 | +SL_X_INTEGRAL_TYPES(SL_X_HINT_REF) | |
112 | +#undef SL_X_HINT_REF | |
113 | + | |
114 | +#ifdef SL_S_ENABLE_POINTERS | |
115 | +# define SL_X_PTR_HINT_REF(X) &(sl_x_ptr_ ## X ## _hint), | |
116 | +SL_X_INTEGRAL_TYPES(SL_X_PTR_HINT_REF) | |
117 | +# undef SL_X_PTR_HINT_REF | |
118 | +#endif | |
119 | + SL_S_NIL | |
120 | +}; | |
121 | + | |
122 | +/*****************************************************************************/ | |
123 | + | |
106 | 124 | static int sl_x_is_builtin(const struct SL_S_Atom *arg){ |
107 | 125 | return (SL_S_IS_NIL(arg) || arg->len > 5) ? 1 : !( |
108 | 126 | SL_S_COMPARE_ATOMS(&sl_x_if, arg) || |
@@ -85,6 +85,10 @@ const extern struct SL_S_Atom | ||
85 | 85 | sl_x_eq, sl_x_ne, sl_x_gt, sl_x_ge, sl_x_lt, sl_x_le; |
86 | 86 | |
87 | 87 | /*****************************************************************************/ |
88 | +/* NULL-terminated. */ | |
89 | +const extern struct SL_S_Atom *const sl_x_all_hints[]; | |
90 | + | |
91 | +/*****************************************************************************/ | |
88 | 92 | |
89 | 93 | struct SL_X_FileOps{ |
90 | 94 | void *x_stdin; |