1 #include "ml_jsencode.h"
2 #include "ml_macros.h"
3 #include "ml_bytecode.h"
4 #include <string.h>
5
6 struct ml_json_encoder_cache_t {
7 inthash_t *Globals;
8 inthash_t Cached[1];
9 int LastIndex;
10 };
11
ml_json_encoder(inthash_t * Globals)12 ml_json_encoder_cache_t *ml_json_encoder(inthash_t *Globals) {
13 ml_json_encoder_cache_t *Cache = new(ml_json_encoder_cache_t);
14 Cache->Globals = Globals;
15 return Cache;
16 }
17
ml_json_encoder_add(ml_json_encoder_cache_t * Cache,ml_value_t * Value,json_t * Json)18 void ml_json_encoder_add(ml_json_encoder_cache_t *Cache, ml_value_t *Value, json_t *Json) {
19 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
20 }
21
ml_json_encode(ml_json_encoder_cache_t * Cache,ml_value_t * Value)22 json_t *ml_json_encode(ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
23 json_t *Json = inthash_search(Cache->Cached, (uintptr_t)Value);
24 if (Json) {
25 json_t *First = json_array_get(Json, 0);
26 if (!json_is_integer(First)) {
27 First = json_integer(Cache->LastIndex++);
28 json_array_insert(Json, 0, First);
29 }
30 return json_pack("[o]", First);
31 }
32 Json = inthash_search(Cache->Globals, (uintptr_t)Value);
33 if (Json) return Json;
34 typeof(ml_json_encode) *encode = ml_typed_fn_get(ml_typeof(Value), ml_json_encode);
35 if (!encode) return json_pack("[ss]", "unsupported", ml_typeof(Value)->Name);
36 return encode(Cache, Value);
37 }
38
ML_TYPED_FN(ml_json_encode,MLNilT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)39 static json_t *ML_TYPED_FN(ml_json_encode, MLNilT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
40 return json_null();
41 }
42
43 extern ml_type_t MLBlankT[];
44
ML_TYPED_FN(ml_json_encode,MLBlankT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)45 static json_t *ML_TYPED_FN(ml_json_encode, MLBlankT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
46 return json_pack("[s]", "blank");
47 }
48
ML_TYPED_FN(ml_json_encode,MLBooleanT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)49 static json_t *ML_TYPED_FN(ml_json_encode, MLBooleanT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
50 return json_boolean(Value == (ml_value_t *)MLTrue);
51 }
52
ML_TYPED_FN(ml_json_encode,MLIntegerT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)53 static json_t *ML_TYPED_FN(ml_json_encode, MLIntegerT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
54 return json_integer(ml_integer_value(Value));
55 }
56
ML_TYPED_FN(ml_json_encode,MLDoubleT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)57 static json_t *ML_TYPED_FN(ml_json_encode, MLDoubleT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
58 return json_real(ml_real_value(Value));
59 }
60
ML_TYPED_FN(ml_json_encode,MLStringT,ml_json_encoder_cache_t * Cache,ml_string_t * Value)61 static json_t *ML_TYPED_FN(ml_json_encode, MLStringT, ml_json_encoder_cache_t *Cache, ml_string_t *Value) {
62 return json_stringn(Value->Value, Value->Length);
63 }
64
ML_TYPED_FN(ml_json_encode,MLRegexT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)65 static json_t *ML_TYPED_FN(ml_json_encode, MLRegexT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
66 return json_pack("[ss]", "regex", ml_regex_pattern(Value));
67 }
68
ML_TYPED_FN(ml_json_encode,MLMethodT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)69 static json_t *ML_TYPED_FN(ml_json_encode, MLMethodT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
70 return json_pack("[ss]", "method", ml_method_name(Value));
71 }
72
ML_TYPED_FN(ml_json_encode,MLListT,ml_json_encoder_cache_t * Cache,ml_list_t * Value)73 static json_t *ML_TYPED_FN(ml_json_encode, MLListT, ml_json_encoder_cache_t *Cache, ml_list_t *Value) {
74 json_t *Json = json_array();
75 json_array_append(Json, json_string("list"));
76 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
77 ML_LIST_FOREACH(Value, Iter) {
78 json_array_append(Json, ml_json_encode(Cache, Iter->Value));
79 }
80 return Json;
81 }
82
ML_TYPED_FN(ml_json_encode,MLNamesT,ml_json_encoder_cache_t * Cache,ml_list_t * Value)83 static json_t *ML_TYPED_FN(ml_json_encode, MLNamesT, ml_json_encoder_cache_t *Cache, ml_list_t *Value) {
84 json_t *Json = json_array();
85 json_array_append(Json, json_string("names"));
86 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
87 ML_LIST_FOREACH(Value, Iter) {
88 json_array_append(Json, ml_json_encode(Cache, Iter->Value));
89 }
90 return Json;
91 }
92
ML_TYPED_FN(ml_json_encode,MLMapT,ml_json_encoder_cache_t * Cache,ml_map_t * Value)93 static json_t *ML_TYPED_FN(ml_json_encode, MLMapT, ml_json_encoder_cache_t *Cache, ml_map_t *Value) {
94 json_t *Json = json_array();
95 json_array_append(Json, json_string("map"));
96 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
97 ML_MAP_FOREACH(Value, Iter) {
98 json_array_append(Json, ml_json_encode(Cache, Iter->Key));
99 json_array_append(Json, ml_json_encode(Cache, Iter->Value));
100 }
101 return Json;
102 }
103
ML_TYPED_FN(ml_json_encode,MLTypeT,ml_json_encoder_cache_t * Cache,ml_type_t * Value)104 static json_t *ML_TYPED_FN(ml_json_encode, MLTypeT, ml_json_encoder_cache_t *Cache, ml_type_t *Value) {
105 return json_pack("[ss]", "type", Value->Name);
106 }
107
ML_TYPED_FN(ml_json_encode,MLGlobalT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)108 static json_t *ML_TYPED_FN(ml_json_encode, MLGlobalT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
109 return ml_json_encode(Cache, ml_global_get(Value));
110 }
111
ML_TYPED_FN(ml_json_encode,MLVariableT,ml_json_encoder_cache_t * Cache,ml_value_t * Value)112 static json_t *ML_TYPED_FN(ml_json_encode, MLVariableT, ml_json_encoder_cache_t *Cache, ml_value_t *Value) {
113 json_t *Json = json_array();
114 json_array_append(Json, json_string("variable"));
115 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
116 return Json;
117 }
118
119 static json_t *ml_closure_info_encode(ml_closure_info_t *Info, ml_json_encoder_cache_t *Cache);
120
ml_closure_inst_encode(ml_inst_t * Inst,ml_json_encoder_cache_t * Cache,json_t * Json,inthash_t * Labels)121 static int ml_closure_inst_encode(ml_inst_t *Inst, ml_json_encoder_cache_t *Cache, json_t *Json, inthash_t *Labels) {
122 json_array_append(Json, json_integer(Inst->Opcode));
123 json_array_append(Json, json_integer(Inst->Line));
124 switch (MLInstTypes[Inst->Opcode]) {
125 case MLIT_NONE:
126 return 1;
127 case MLIT_INST:
128 json_array_append(Json, json_integer((uintptr_t)inthash_search(Labels, Inst[1].Inst->Label)));
129 return 2;
130 case MLIT_INST_TYPES: {
131 json_array_append(Json, json_integer((uintptr_t)inthash_search(Labels, Inst[1].Inst->Label)));
132 json_t *Types = json_array();
133 for (const char **Ptr= Inst[2].Ptrs; *Ptr; ++Ptr) {
134 json_array_append(Types, json_string(*Ptr));
135 }
136 return 3;
137 }
138 case MLIT_COUNT_COUNT:
139 json_array_append(Json, json_integer(Inst[1].Count));
140 json_array_append(Json, json_integer(Inst[2].Count));
141 return 3;
142 case MLIT_COUNT:
143 json_array_append(Json, json_integer(Inst[1].Count));
144 return 2;
145 case MLIT_INDEX:
146 json_array_append(Json, json_integer(Inst[1].Index));
147 return 2;
148 case MLIT_VALUE:
149 json_array_append(Json, ml_json_encode(Cache, Inst[1].Value));
150 return 2;
151 case MLIT_VALUE_VALUE:
152 json_array_append(Json, ml_json_encode(Cache, Inst[1].Value));
153 json_array_append(Json, ml_json_encode(Cache, Inst[2].Value));
154 return 3;
155 case MLIT_INDEX_COUNT:
156 json_array_append(Json, json_integer(Inst[1].Index));
157 json_array_append(Json, json_integer(Inst[2].Count));
158 return 3;
159 case MLIT_INDEX_CHARS:
160 json_array_append(Json, json_integer(Inst[1].Index));
161 json_array_append(Json, json_string(Inst[2].Chars));
162 return 3;
163 case MLIT_COUNT_VALUE:
164 json_array_append(Json, json_integer(Inst[1].Count));
165 json_array_append(Json, ml_json_encode(Cache, Inst[2].Value));
166 return 3;
167 case MLIT_COUNT_CHARS:
168 json_array_append(Json, json_stringn(Inst[2].Chars, Inst[1].Count));
169 return 3;
170 case MLIT_DECL:
171 return 2;
172 case MLIT_INDEX_DECL:
173 json_array_append(Json, json_integer(Inst[1].Index));
174 return 3;
175 case MLIT_COUNT_DECL:
176 json_array_append(Json, json_integer(Inst[1].Count));
177 return 3;
178 case MLIT_COUNT_COUNT_DECL:
179 json_array_append(Json, json_integer(Inst[1].Count));
180 json_array_append(Json, json_integer(Inst[2].Count));
181 return 4;
182 case MLIT_CLOSURE: {
183 ml_closure_info_t *Info = Inst[1].ClosureInfo;
184 json_array_append(Json, ml_closure_info_encode(Info, Cache));
185 for (int N = 0; N < Info->NumUpValues; ++N) {
186 json_array_append(Json, json_integer(Inst[2 + N].Index));
187 }
188 return 2 + Inst[1].ClosureInfo->NumUpValues;
189 }
190 case MLIT_SWITCH: {
191 json_t *Insts = json_array();
192 json_array_append(Insts, json_string("list"));
193 for (int N = 0; N < Inst[1].Count; ++N) {
194 json_array_append(Insts, json_integer(Inst[2].Insts[N]->Label));
195 }
196 json_array_append(Json, Insts);
197 return 3;
198 }
199 default: return 0;
200 }
201 }
202
ml_closure_info_param_fn(const char * Name,void * Index,json_t * Params)203 static int ml_closure_info_param_fn(const char *Name, void *Index, json_t *Params) {
204 json_array_set(Params, (intptr_t)Index - 1, json_string(Name));
205 return 0;
206 }
207
ml_closure_find_labels(ml_inst_t * Inst,uintptr_t * Offset)208 static int ml_closure_find_labels(ml_inst_t *Inst, uintptr_t *Offset) {
209 switch (MLInstTypes[Inst->Opcode]) {
210 case MLIT_NONE: *Offset += 2; return 1;
211 case MLIT_INST: *Offset += 3; return 2;
212 case MLIT_INST_TYPES: *Offset += 4; return 3;
213 case MLIT_COUNT_COUNT: *Offset += 4; return 3;
214 case MLIT_COUNT: *Offset += 3; return 2;
215 case MLIT_INDEX: *Offset += 3; return 2;
216 case MLIT_VALUE: *Offset += 3; return 2;
217 case MLIT_VALUE_VALUE: *Offset += 4; return 3;
218 case MLIT_INDEX_COUNT: *Offset += 4; return 3;
219 case MLIT_INDEX_CHARS: *Offset += 4; return 3;
220 case MLIT_COUNT_VALUE: *Offset += 4; return 3;
221 case MLIT_COUNT_CHARS: *Offset += 3; return 3;
222 case MLIT_DECL: *Offset += 2; return 2;
223 case MLIT_INDEX_DECL: *Offset += 3; return 3;
224 case MLIT_COUNT_DECL: *Offset += 3; return 3;
225 case MLIT_COUNT_COUNT_DECL: *Offset += 4; return 4;
226 case MLIT_CLOSURE:
227 *Offset += 3 + Inst[1].ClosureInfo->NumUpValues;
228 return 2 + Inst[1].ClosureInfo->NumUpValues;
229 case MLIT_SWITCH:
230 return 3;
231 default: return 0;
232 }
233 }
234
ml_closure_info_encode(ml_closure_info_t * Info,ml_json_encoder_cache_t * Cache)235 static json_t *ml_closure_info_encode(ml_closure_info_t *Info, ml_json_encoder_cache_t *Cache) {
236 json_t *Json = json_array();
237 json_array_append(Json, json_string("!"));
238 json_array_append(Json, json_string(Info->Source ?: ""));
239 json_array_append(Json, json_integer(Info->StartLine));
240 json_array_append(Json, json_integer(Info->FrameSize));
241 json_array_append(Json, json_integer(Info->NumParams));
242 json_array_append(Json, json_integer(Info->NumUpValues));
243 json_array_append(Json, json_integer(Info->ExtraArgs));
244 json_array_append(Json, json_integer(Info->NamedArgs));
245 json_t *Params = json_array();
246 for (int I = 0; I < Info->Params->Size; ++I) json_array_append(Params, json_null());
247 stringmap_foreach(Info->Params, Params, (void *)ml_closure_info_param_fn);
248 json_array_append(Json, Params);
249 json_t *Instructions = json_array();
250 inthash_t Labels[1] = {INTHASH_INIT};
251 uintptr_t Offset = 0, Return = 0;
252 ml_closure_info_labels(Info);
253 for (ml_inst_t *Inst = Info->Entry; Inst != Info->Halt;) {
254 if (Inst->Label) inthash_insert(Labels, Inst->Label, (void *)Offset);
255 if (Inst->Opcode == MLI_LINK) {
256 Inst = Inst[1].Inst;
257 } else {
258 if (Inst == Info->Return) Return = Offset;
259 Inst += ml_closure_find_labels(Inst, &Offset);
260 }
261 }
262 for (ml_inst_t *Inst = Info->Entry; Inst != Info->Halt;) {
263 if (Inst->Opcode == MLI_LINK) {
264 Inst = Inst[1].Inst;
265 } else {
266 Inst += ml_closure_inst_encode(Inst, Cache, Instructions, Labels);
267 }
268 }
269 json_array_append(Json, json_integer(0));
270 json_array_append(Json, json_integer(Return));
271 json_array_append(Json, Instructions);
272 return Json;
273 }
274
275
ML_TYPED_FN(ml_json_encode,MLClosureT,ml_json_encoder_cache_t * Cache,ml_closure_t * Value)276 static json_t *ML_TYPED_FN(ml_json_encode, MLClosureT, ml_json_encoder_cache_t *Cache, ml_closure_t *Value) {
277 json_t *Json = json_array();
278 json_array_append(Json, json_string("closure"));
279 inthash_insert(Cache->Cached, (uintptr_t)Value, Json);
280 ml_closure_info_t *Info = Value->Info;
281 json_array_append(Json, ml_closure_info_encode(Info, Cache));
282 for (int I = 0; I < Info->NumUpValues; ++I) {
283 json_array_append(Json, ml_json_encode(Cache, Value->UpValues[I]));
284 }
285 return Json;
286 }
287
288 typedef struct {
289 ml_type_t *Type;
290 json_t *Json;
291 } ml_json_value_t;
292
293 extern ml_type_t JSValueT[1];
294
ML_FUNCTION(JSValue)295 ML_FUNCTION(JSValue) {
296 ML_CHECK_ARG_COUNT(1);
297 ML_CHECK_ARG_TYPE(0, MLStringT);
298 ml_json_value_t *Value = new(ml_json_value_t);
299 Value->Type = JSValueT;
300 Value->Json = json_pack("[ss]", "^", ml_string_value(Args[0]));
301 return (ml_value_t *)Value;
302 }
303
304 ML_TYPE(JSValueT, (), "js-value",
305 .Constructor = (ml_value_t *)JSValue
306 );
307
ML_TYPED_FN(ml_json_encode,JSValueT,ml_json_encoder_cache_t * Cache,ml_json_value_t * Value)308 static json_t *ML_TYPED_FN(ml_json_encode, JSValueT, ml_json_encoder_cache_t *Cache, ml_json_value_t *Value) {
309 return Value->Json;
310 }
311
312 typedef struct {
313 ml_type_t *Type;
314 inthash_t Globals[1];
315 } ml_json_encoder_t;
316
317 extern ml_type_t JSEncoderT[1];
318
ML_FUNCTION(JSEncoder)319 ML_FUNCTION(JSEncoder) {
320 ml_json_encoder_t *Encoder = new(ml_json_encoder_t);
321 Encoder->Type = JSEncoderT;
322 return (ml_value_t *)Encoder;
323 }
324
325 ML_TYPE(JSEncoderT, (), "js-encoder",
326 .Constructor = (ml_value_t *)JSEncoder
327 );
328
329 ML_METHOD("add", JSEncoderT, MLAnyT, MLStringT) {
330 ml_json_encoder_t *Encoder = (ml_json_encoder_t *)Args[0];
331 inthash_insert(Encoder->Globals,
332 (uintptr_t)Args[1],
333 json_pack("[ss]", "^", ml_string_value(Args[2]))
334 );
335 return Args[0];
336 }
337
338 ML_METHOD("encode", JSEncoderT, MLAnyT) {
339 ml_json_encoder_t *Encoder = (ml_json_encoder_t *)Args[0];
340 ml_json_encoder_cache_t Cache[1] = {0,};
341 Cache->Globals = Encoder->Globals;
342 json_t *Json = ml_json_encode(Cache, Args[1]);
343 const char *String = json_dumps(Json, JSON_ENCODE_ANY | JSON_COMPACT);
344 return ml_cstring(String);
345 }
346
347 struct json_decoder_cache_t {
348 stringmap_t *Globals;
349 inthash_t Cached[1];
350 };
351
352 typedef struct {
353 ml_type_t *Type;
354 stringmap_t Globals[1];
355 } ml_json_decoder_t;
356
357 extern ml_type_t JSDecoderT[1];
358
ML_FUNCTION(JSDecoder)359 ML_FUNCTION(JSDecoder) {
360 ml_json_decoder_t *Decoder = new(ml_json_decoder_t);
361 Decoder->Type = JSDecoderT;
362 return (ml_value_t *)Decoder;
363 }
364
365 ML_TYPE(JSDecoderT, (), "js-decoder",
366 .Constructor = (ml_value_t *)JSDecoder
367 );
368
369 ML_METHOD("decode", JSDecoderT, MLAnyT) {
370 ml_json_decoder_t Decoder[1] = {0,};
371 }
372
ml_jsencode_init(stringmap_t * Globals)373 void ml_jsencode_init(stringmap_t *Globals) {
374 #include "ml_jsencode_init.c"
375 if (Globals) {
376 stringmap_insert(Globals, "jsvalue", JSValue);
377 stringmap_insert(Globals, "jsencoder", JSEncoderT);
378 stringmap_insert(Globals, "jsdecoder", JSDecoderT);
379 }
380 }
381