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