1 |
|
|
/* |
2 |
|
|
Copyright 2019, 2021, 2022, 2024 Joel Svensson svenssonjoel@yahoo.se |
3 |
|
|
2022 Benjamin Vedder |
4 |
|
|
|
5 |
|
|
This program is free software: you can redistribute it and/or modify |
6 |
|
|
it under the terms of the GNU General Public License as published by |
7 |
|
|
the Free Software Foundation, either version 3 of the License, or |
8 |
|
|
(at your option) any later version. |
9 |
|
|
|
10 |
|
|
This program is distributed in the hope that it will be useful, |
11 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
GNU General Public License for more details. |
14 |
|
|
|
15 |
|
|
You should have received a copy of the GNU General Public License |
16 |
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <lbm_memory.h> |
20 |
|
|
#include <stdio.h> |
21 |
|
|
#include <stdlib.h> |
22 |
|
|
#include <stdbool.h> |
23 |
|
|
#include <string.h> |
24 |
|
|
#include <eval_cps.h> |
25 |
|
|
|
26 |
|
|
#include "extensions.h" |
27 |
|
|
#include "lbm_utils.h" |
28 |
|
|
|
29 |
|
|
static lbm_uint ext_max = 0; |
30 |
|
|
static lbm_uint next_extension_ix = 0; |
31 |
|
|
|
32 |
|
|
lbm_extension_t *extension_table = NULL; |
33 |
|
|
|
34 |
|
|
void lbm_extensions_set_next(lbm_uint i) { |
35 |
|
|
next_extension_ix = i; |
36 |
|
|
} |
37 |
|
|
|
38 |
|
|
lbm_value lbm_extensions_default(lbm_value *args, lbm_uint argn) { |
39 |
|
|
(void)args; |
40 |
|
|
(void)argn; |
41 |
|
|
return ENC_SYM_EERROR; |
42 |
|
|
} |
43 |
|
|
|
44 |
|
21924 |
int lbm_extensions_init(lbm_extension_t *extension_storage, lbm_uint extension_storage_size) { |
45 |
✓✗✗✓
|
21924 |
if (extension_storage == NULL || extension_storage_size == 0) return 0; |
46 |
|
|
|
47 |
|
21924 |
extension_table = extension_storage; |
48 |
|
21924 |
memset(extension_table, 0, sizeof(lbm_extension_t) * extension_storage_size); |
49 |
|
|
|
50 |
✓✓ |
4406724 |
for (lbm_uint i = 0; i < extension_storage_size; i ++) { |
51 |
|
4384800 |
extension_storage[i].fptr = lbm_extensions_default; |
52 |
|
|
} |
53 |
|
|
|
54 |
|
21924 |
next_extension_ix = 0; |
55 |
|
21924 |
ext_max = (lbm_uint)extension_storage_size; |
56 |
|
|
|
57 |
|
21924 |
return 1; |
58 |
|
|
} |
59 |
|
|
|
60 |
|
689884832 |
lbm_uint lbm_get_max_extensions(void) { |
61 |
|
689884832 |
return ext_max; |
62 |
|
|
} |
63 |
|
|
|
64 |
|
21924 |
lbm_uint lbm_get_num_extensions(void) { |
65 |
|
21924 |
return next_extension_ix; |
66 |
|
|
} |
67 |
|
|
|
68 |
|
14 |
extension_fptr lbm_get_extension(lbm_uint sym) { |
69 |
|
14 |
lbm_uint ext_next = sym - EXTENSION_SYMBOLS_START; |
70 |
✗✓ |
14 |
if (ext_next >= ext_max) { |
71 |
|
|
return NULL; |
72 |
|
|
} |
73 |
|
14 |
return extension_table[ext_next].fptr; |
74 |
|
|
} |
75 |
|
|
|
76 |
|
|
bool lbm_clr_extension(lbm_uint sym_id) { |
77 |
|
|
lbm_uint ext_id = SYMBOL_IX(sym_id); |
78 |
|
|
if (ext_id >= ext_max) { |
79 |
|
|
return false; |
80 |
|
|
} |
81 |
|
|
extension_table[ext_id].name = NULL; |
82 |
|
|
extension_table[ext_id].fptr = lbm_extensions_default; |
83 |
|
|
return true; |
84 |
|
|
} |
85 |
|
|
|
86 |
|
14 |
bool lbm_lookup_extension_id(char *sym_str, lbm_uint *ix) { |
87 |
✓✗ |
1484 |
for (lbm_uint i = 0; i < ext_max; i ++) { |
88 |
✓✗ |
1484 |
if(extension_table[i].name) { |
89 |
✓✓ |
1484 |
if (str_eq(extension_table[i].name, sym_str)) { |
90 |
|
14 |
*ix = i + EXTENSION_SYMBOLS_START; |
91 |
|
14 |
return true; |
92 |
|
|
} |
93 |
|
|
} |
94 |
|
|
} |
95 |
|
|
return false; |
96 |
|
|
} |
97 |
|
|
|
98 |
|
2302062 |
bool lbm_add_extension(char *sym_str, extension_fptr ext) { |
99 |
|
|
lbm_value symbol; |
100 |
|
|
|
101 |
|
|
// symbol_by_name loops through all symbols. It may be enough |
102 |
|
|
// to search only the extension table, but unsure what the effect will |
103 |
|
|
// be if adding an extension with same str-name as a built-in or special |
104 |
|
|
// form. The extension may override built-in... |
105 |
|
|
// |
106 |
|
|
// Check if symbol already exists. |
107 |
✓✓ |
2302062 |
if (lbm_get_symbol_by_name(sym_str, &symbol)) { |
108 |
✓✗ |
14 |
if (lbm_is_extension(lbm_enc_sym(symbol))) { |
109 |
|
|
// update the extension entry. |
110 |
|
14 |
extension_table[SYMBOL_IX(symbol)].fptr = ext; |
111 |
|
14 |
return true; |
112 |
|
|
} |
113 |
|
|
return false; |
114 |
|
|
} |
115 |
|
|
|
116 |
✓✗ |
2302048 |
if (next_extension_ix < ext_max) { |
117 |
|
2302048 |
lbm_uint sym_ix = next_extension_ix ++; |
118 |
|
2302048 |
extension_table[sym_ix].name = sym_str; |
119 |
|
2302048 |
extension_table[sym_ix].fptr = ext; |
120 |
|
2302048 |
return true; |
121 |
|
|
} |
122 |
|
|
return false; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
// Helpers for extension developers: |
126 |
|
|
|
127 |
|
3164 |
static bool lbm_is_number_all(lbm_value *args, lbm_uint argn) { |
128 |
✓✓ |
9940 |
for (lbm_uint i = 0;i < argn;i++) { |
129 |
✗✓ |
6776 |
if (!lbm_is_number(args[i])) { |
130 |
|
|
return false; |
131 |
|
|
} |
132 |
|
|
} |
133 |
|
3164 |
return true; |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
bool lbm_check_true_false(lbm_value v) { |
137 |
|
|
bool res = lbm_is_symbol_true(v) || lbm_is_symbol_nil(v); |
138 |
|
|
lbm_set_error_reason((char*)lbm_error_str_not_a_boolean); |
139 |
|
|
return res; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
2212 |
bool lbm_check_number_all(lbm_value *args, lbm_uint argn) { |
143 |
✗✓ |
2212 |
if (!lbm_is_number_all(args, argn)) { |
144 |
|
|
lbm_set_error_reason((char*)lbm_error_str_no_number); |
145 |
|
|
return false; |
146 |
|
|
} |
147 |
|
2212 |
return true; |
148 |
|
|
} |
149 |
|
|
|
150 |
|
84 |
bool lbm_check_argn(lbm_uint argn, lbm_uint n) { |
151 |
✓✓ |
84 |
if (argn != n) { |
152 |
|
28 |
lbm_set_error_reason((char*)lbm_error_str_num_args); |
153 |
|
28 |
return false; |
154 |
|
|
} else { |
155 |
|
56 |
return true; |
156 |
|
|
} |
157 |
|
|
} |
158 |
|
|
|
159 |
|
952 |
bool lbm_check_argn_number(lbm_value *args, lbm_uint argn, lbm_uint n) { |
160 |
✗✓ |
952 |
if (!lbm_is_number_all(args, argn)) { |
161 |
|
|
lbm_set_error_reason((char*)lbm_error_str_no_number); |
162 |
|
|
return false; |
163 |
✓✓ |
952 |
} else if (argn != n) { |
164 |
|
420 |
lbm_set_error_reason((char*)lbm_error_str_num_args); |
165 |
|
420 |
return false; |
166 |
|
|
} else { |
167 |
|
532 |
return true; |
168 |
|
|
} |
169 |
|
|
} |
170 |
|
|
|
171 |
|
10316 |
lbm_value make_list(int num, ...) { |
172 |
|
|
va_list arguments; |
173 |
|
10316 |
va_start (arguments, num); |
174 |
|
10316 |
lbm_value res = ENC_SYM_NIL; |
175 |
✓✓ |
36304 |
for (int i = 0; i < num; i++) { |
176 |
|
25988 |
res = lbm_cons(va_arg(arguments, lbm_value), res); |
177 |
|
|
} |
178 |
|
10316 |
va_end (arguments); |
179 |
|
10316 |
return lbm_list_destructive_reverse(res); |
180 |
|
|
} |
181 |
|
|
|
182 |
|
13068 |
bool strmatch(const char *str1, const char *str2) { |
183 |
|
13068 |
size_t len = strlen(str1); |
184 |
|
|
|
185 |
✓✓ |
13068 |
if (str2[len] != ' ') { |
186 |
|
10074 |
return false; |
187 |
|
|
} |
188 |
|
|
|
189 |
|
2994 |
bool same = true; |
190 |
✓✓ |
13872 |
for (unsigned int i = 0;i < len;i++) { |
191 |
✓✓ |
12922 |
if (str1[i] != str2[i]) { |
192 |
|
2044 |
same = false; |
193 |
|
2044 |
break; |
194 |
|
|
} |
195 |
|
|
} |
196 |
|
|
|
197 |
|
2994 |
return same; |
198 |
|
|
} |