jsonnet 0.1.0 → 0.4.0

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.
@@ -0,0 +1,206 @@
1
+ #include <libjsonnet.h>
2
+ #include <ruby/ruby.h>
3
+ #include <ruby/intern.h>
4
+
5
+ #include "ruby_jsonnet.h"
6
+
7
+ static struct JsonnetJsonValue *protect_obj_to_json(struct JsonnetVm *vm, VALUE obj,
8
+ struct JsonnetJsonValue *parent);
9
+
10
+ /**
11
+ * Converts a Jsonnet JSON value into a Ruby object.
12
+ *
13
+ * Arrays and objects in JSON are not supported due to the limitation of
14
+ * libjsonnet API.
15
+ */
16
+ VALUE
17
+ rubyjsonnet_json_to_obj(struct JsonnetVm *vm, const struct JsonnetJsonValue *value)
18
+ {
19
+ union {
20
+ const char *str;
21
+ double num;
22
+ } typed_value;
23
+
24
+ if ((typed_value.str = jsonnet_json_extract_string(vm, value))) {
25
+ return rb_enc_str_new_cstr(typed_value.str, rb_utf8_encoding());
26
+ }
27
+ if (jsonnet_json_extract_number(vm, value, &typed_value.num)) {
28
+ return DBL2NUM(typed_value.num);
29
+ }
30
+
31
+ switch (jsonnet_json_extract_bool(vm, value)) {
32
+ case 0:
33
+ return Qfalse;
34
+ case 1:
35
+ return Qtrue;
36
+ case 2:
37
+ break;
38
+ default:
39
+ /* never happens */
40
+ rb_raise(rb_eRuntimeError, "unrecognized json bool value");
41
+ }
42
+ if (jsonnet_json_extract_null(vm, value)) {
43
+ return Qnil;
44
+ }
45
+
46
+ /* TODO: support arrays and objects when they get accessible */
47
+ rb_raise(rb_eArgError, "unsupported type of JSON value");
48
+ }
49
+
50
+ static struct JsonnetJsonValue *
51
+ string_to_json(struct JsonnetVm *vm, VALUE str)
52
+ {
53
+ rubyjsonnet_assert_asciicompat(str);
54
+ return jsonnet_json_make_string(vm, RSTRING_PTR(str));
55
+ }
56
+
57
+ static struct JsonnetJsonValue *
58
+ num_to_json(struct JsonnetVm *vm, VALUE n)
59
+ {
60
+ return jsonnet_json_make_number(vm, NUM2DBL(n));
61
+ }
62
+
63
+ static struct JsonnetJsonValue *
64
+ ary_to_json(struct JsonnetVm *vm, VALUE ary)
65
+ {
66
+ struct JsonnetJsonValue *const json_array = jsonnet_json_make_array(vm);
67
+
68
+ int i;
69
+ for (i = 0; i < RARRAY_LEN(ary); ++i) {
70
+ struct JsonnetJsonValue *const v = protect_obj_to_json(vm, RARRAY_AREF(ary, i), json_array);
71
+ jsonnet_json_array_append(vm, json_array, v);
72
+ }
73
+ return json_array;
74
+ }
75
+
76
+ struct hash_to_json_params {
77
+ struct JsonnetVm *vm;
78
+ struct JsonnetJsonValue *obj;
79
+ };
80
+
81
+ static int
82
+ hash_item_to_json(VALUE key, VALUE value, VALUE paramsval)
83
+ {
84
+ const struct hash_to_json_params *const params = (const struct hash_to_json_params *)paramsval;
85
+
86
+ StringValue(key);
87
+ rubyjsonnet_assert_asciicompat(key);
88
+
89
+ jsonnet_json_object_append(params->vm, params->obj, StringValueCStr(key),
90
+ protect_obj_to_json(params->vm, value, params->obj));
91
+
92
+ return ST_CONTINUE;
93
+ }
94
+
95
+ static struct JsonnetJsonValue *
96
+ hash_to_json(struct JsonnetVm *vm, VALUE hash)
97
+ {
98
+ struct JsonnetJsonValue *const json_obj = jsonnet_json_make_object(vm);
99
+ const struct hash_to_json_params args = {vm, json_obj};
100
+ rb_hash_foreach(hash, hash_item_to_json, (VALUE)&args);
101
+ return json_obj;
102
+ }
103
+
104
+ /**
105
+ * Converts a Ruby object into a Jsonnet JSON value
106
+ *
107
+ * TODO(yugui): Safely destorys an intermediate object on exception.
108
+ */
109
+ static struct JsonnetJsonValue *
110
+ obj_to_json(struct JsonnetVm *vm, VALUE obj)
111
+ {
112
+ VALUE converted;
113
+
114
+ switch (obj) {
115
+ case Qnil:
116
+ return jsonnet_json_make_null(vm);
117
+ case Qtrue:
118
+ return jsonnet_json_make_bool(vm, 1);
119
+ case Qfalse:
120
+ return jsonnet_json_make_bool(vm, 0);
121
+ }
122
+
123
+ converted = rb_check_string_type(obj);
124
+ if (converted != Qnil) {
125
+ return string_to_json(vm, converted);
126
+ }
127
+
128
+ converted = rb_check_to_float(obj);
129
+ if (converted != Qnil) {
130
+ return num_to_json(vm, converted);
131
+ }
132
+
133
+ converted = rb_check_array_type(obj);
134
+ if (converted != Qnil) {
135
+ return ary_to_json(vm, converted);
136
+ }
137
+
138
+ converted = rb_check_hash_type(obj);
139
+ if (converted != Qnil) {
140
+ return hash_to_json(vm, converted);
141
+ }
142
+
143
+ converted = rb_any_to_s(obj);
144
+ return string_to_json(vm, converted);
145
+ }
146
+
147
+ struct protect_args {
148
+ struct JsonnetVm *vm;
149
+ VALUE obj;
150
+ };
151
+
152
+ static VALUE
153
+ protect_obj_to_json_block(VALUE paramsval)
154
+ {
155
+ const struct protect_args *const params = (const struct protect_args *)paramsval;
156
+ return (VALUE)obj_to_json(params->vm, params->obj);
157
+ }
158
+
159
+ /**
160
+ * Safely converts a Ruby object into a JSON value.
161
+ *
162
+ * It automatically destroys \a parent on exception.
163
+ * @param[in] vm a Jsonnet VM
164
+ * @param[in] obj a Ruby object to be converted
165
+ * @param[in] parent destroys this value on failure
166
+ * @throws can throw \c TypeError or other exceptions
167
+ */
168
+ static struct JsonnetJsonValue *
169
+ protect_obj_to_json(struct JsonnetVm *vm, VALUE obj, struct JsonnetJsonValue *parent)
170
+ {
171
+ const struct protect_args args = {vm, obj};
172
+ int state = 0;
173
+
174
+ VALUE result = rb_protect(protect_obj_to_json_block, (VALUE)&args, &state);
175
+ if (!state) {
176
+ return (struct JsonnetJsonValue *)result;
177
+ }
178
+
179
+ jsonnet_json_destroy(vm, parent);
180
+ rb_jump_tag(state);
181
+ }
182
+
183
+ /**
184
+ * Converts a Ruby object into a JSON value.
185
+ * Returns an error message on failure.
186
+ *
187
+ * @param[in] vm a Jsonnet VM
188
+ * @param[in] obj a Ruby object to be converted
189
+ * @param[out] success set to 1 on success, set to 0 on failure.
190
+ * @returns the converted value on success, an error message on failure.
191
+ */
192
+ struct JsonnetJsonValue *
193
+ rubyjsonnet_obj_to_json(struct JsonnetVm *vm, VALUE obj, int *success)
194
+ {
195
+ int state = 0;
196
+ const struct protect_args args = {vm, obj};
197
+ VALUE result = rb_protect(protect_obj_to_json_block, (VALUE)&args, &state);
198
+ if (state) {
199
+ const VALUE msg = rubyjsonnet_format_exception(rb_errinfo());
200
+ rb_set_errinfo(Qnil);
201
+ *success = 0;
202
+ return string_to_json(vm, msg);
203
+ }
204
+ *success = 1;
205
+ return (struct JsonnetJsonValue *)result;
206
+ }
@@ -0,0 +1,39 @@
1
+ #ifndef RUBY_JSONNET_RUBY_JSONNET_H_
2
+ #define RUBY_JSONNET_RUBY_JSONNET_H_
3
+
4
+ #include <ruby/ruby.h>
5
+ #include <ruby/encoding.h>
6
+
7
+ extern const rb_data_type_t jsonnet_vm_type;
8
+
9
+ struct native_callback_ctx {
10
+ VALUE callback;
11
+ long arity;
12
+ VALUE vm;
13
+ };
14
+
15
+ struct jsonnet_vm_wrap {
16
+ struct JsonnetVm *vm;
17
+
18
+ VALUE import_callback;
19
+ struct {
20
+ long len;
21
+ struct native_callback_ctx **contexts;
22
+ } native_callbacks;
23
+ };
24
+
25
+ void rubyjsonnet_init_vm(VALUE mod);
26
+ void rubyjsonnet_init_callbacks(VALUE cVM);
27
+ void rubyjsonnet_init_helpers(VALUE mod);
28
+
29
+ struct jsonnet_vm_wrap *rubyjsonnet_obj_to_vm(VALUE vm);
30
+
31
+ VALUE rubyjsonnet_json_to_obj(struct JsonnetVm *vm, const struct JsonnetJsonValue *value);
32
+ struct JsonnetJsonValue *rubyjsonnet_obj_to_json(struct JsonnetVm *vm, VALUE obj, int *success);
33
+
34
+ rb_encoding *rubyjsonnet_assert_asciicompat(VALUE str);
35
+ char *rubyjsonnet_str_to_cstr(struct JsonnetVm *vm, VALUE str);
36
+ VALUE rubyjsonnet_format_exception(VALUE exc);
37
+ int rubyjsonnet_jump_tag(const char *exc_mesg);
38
+
39
+ #endif /* RUBY_JSONNET_RUBY_JSONNET_H_ */
@@ -0,0 +1,508 @@
1
+ #include <libjsonnet.h>
2
+ #ifdef HAVE_LIBJSONNET_FMT_H
3
+ # include <libjsonnet_fmt.h>
4
+ #endif
5
+ #include <ruby/ruby.h>
6
+ #include <ruby/intern.h>
7
+
8
+ #include "ruby_jsonnet.h"
9
+
10
+ /*
11
+ * defines the core part of Jsonnet::VM
12
+ */
13
+
14
+ /*
15
+ * Jsonnet evaluator
16
+ *
17
+ * call-seq:
18
+ * Jsonnet::VM
19
+ */
20
+ static VALUE cVM;
21
+
22
+ /*
23
+ * Raised on evaluation errors in a Jsonnet VM.
24
+ */
25
+ static VALUE eEvaluationError;
26
+ static VALUE eFormatError;
27
+
28
+ static void raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc);
29
+ static void raise_format_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc);
30
+ static VALUE str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc);
31
+ static VALUE fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc);
32
+
33
+ static void vm_free(void *ptr);
34
+ static void vm_mark(void *ptr);
35
+
36
+ const rb_data_type_t jsonnet_vm_type = {
37
+ "JsonnetVm",
38
+ {
39
+ /* dmark = */ vm_mark,
40
+ /* dfree = */ vm_free,
41
+ /* dsize = */ 0,
42
+ },
43
+ /* parent = */ 0,
44
+ /* data = */ 0,
45
+ /* flags = */ RUBY_TYPED_FREE_IMMEDIATELY,
46
+ };
47
+
48
+ struct jsonnet_vm_wrap *
49
+ rubyjsonnet_obj_to_vm(VALUE wrap)
50
+ {
51
+ struct jsonnet_vm_wrap *vm;
52
+ TypedData_Get_Struct(wrap, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
53
+
54
+ return vm;
55
+ }
56
+
57
+ static VALUE
58
+ vm_s_new(int argc, const VALUE *argv, VALUE klass)
59
+ {
60
+ struct jsonnet_vm_wrap *vm;
61
+ VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
62
+ vm->vm = jsonnet_make();
63
+ vm->import_callback = Qnil;
64
+ vm->native_callbacks.len = 0;
65
+ vm->native_callbacks.contexts = NULL;
66
+
67
+ rb_obj_call_init(self, argc, argv);
68
+ return self;
69
+ }
70
+
71
+ static void
72
+ vm_free(void *ptr)
73
+ {
74
+ int i;
75
+ struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
76
+ jsonnet_destroy(vm->vm);
77
+
78
+ for (i = 0; i < vm->native_callbacks.len; ++i) {
79
+ struct native_callback_ctx *ctx = vm->native_callbacks.contexts[i];
80
+ RB_REALLOC_N(ctx, struct native_callback_ctx, 0);
81
+ }
82
+ RB_REALLOC_N(vm->native_callbacks.contexts, struct native_callback_ctx *, 0);
83
+
84
+ RB_REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
85
+ }
86
+
87
+ static void
88
+ vm_mark(void *ptr)
89
+ {
90
+ int i;
91
+ struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
92
+
93
+ rb_gc_mark(vm->import_callback);
94
+ for (i = 0; i < vm->native_callbacks.len; ++i) {
95
+ rb_gc_mark(vm->native_callbacks.contexts[i]->callback);
96
+ }
97
+ }
98
+
99
+ static VALUE
100
+ vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
101
+ {
102
+ int error;
103
+ char *result;
104
+ rb_encoding *const enc = rb_to_encoding(encoding);
105
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
106
+
107
+ FilePathValue(fname);
108
+ if (RTEST(multi_p)) {
109
+ result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
110
+ } else {
111
+ result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
112
+ }
113
+
114
+ if (error) {
115
+ raise_eval_error(vm->vm, result, rb_enc_get(fname));
116
+ }
117
+ return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
118
+ }
119
+
120
+ static VALUE
121
+ vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
122
+ {
123
+ int error;
124
+ char *result;
125
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
126
+
127
+ rb_encoding *enc = rubyjsonnet_assert_asciicompat(StringValue(snippet));
128
+ FilePathValue(fname);
129
+ if (RTEST(multi_p)) {
130
+ result = jsonnet_evaluate_snippet_multi(vm->vm, StringValueCStr(fname),
131
+ StringValueCStr(snippet), &error);
132
+ } else {
133
+ result = jsonnet_evaluate_snippet(vm->vm, StringValueCStr(fname), StringValueCStr(snippet),
134
+ &error);
135
+ }
136
+
137
+ if (error) {
138
+ raise_eval_error(vm->vm, result, rb_enc_get(fname));
139
+ }
140
+ return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
141
+ }
142
+
143
+ #define vm_bind_variable(type, self, key, val) \
144
+ do { \
145
+ struct jsonnet_vm_wrap *vm; \
146
+ \
147
+ rubyjsonnet_assert_asciicompat(StringValue(key)); \
148
+ rubyjsonnet_assert_asciicompat(StringValue(val)); \
149
+ TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm); \
150
+ jsonnet_##type(vm->vm, StringValueCStr(key), StringValueCStr(val)); \
151
+ } while (0)
152
+
153
+ /*
154
+ * Binds an external variable to a value.
155
+ * @param [String] key name of the variable
156
+ * @param [String] val the value
157
+ */
158
+ static VALUE
159
+ vm_ext_var(VALUE self, VALUE key, VALUE val)
160
+ {
161
+ vm_bind_variable(ext_var, self, key, val);
162
+ return Qnil;
163
+ }
164
+
165
+ /*
166
+ * Binds an external variable to a code fragment.
167
+ * @param [String] key name of the variable
168
+ * @param [String] code Jsonnet expression
169
+ */
170
+ static VALUE
171
+ vm_ext_code(VALUE self, VALUE key, VALUE code)
172
+ {
173
+ vm_bind_variable(ext_code, self, key, code);
174
+ return Qnil;
175
+ }
176
+
177
+ /*
178
+ * Binds a top-level argument to a value.
179
+ * @param [String] key name of the variable
180
+ * @param [String] val the value
181
+ */
182
+ static VALUE
183
+ vm_tla_var(VALUE self, VALUE key, VALUE val)
184
+ {
185
+ vm_bind_variable(tla_var, self, key, val);
186
+ return Qnil;
187
+ }
188
+
189
+ /*
190
+ * Binds a top-level argument to a code fragment.
191
+ * @param [String] key name of the variable
192
+ * @param [String] code Jsonnet expression
193
+ */
194
+ static VALUE
195
+ vm_tla_code(VALUE self, VALUE key, VALUE code)
196
+ {
197
+ vm_bind_variable(tla_code, self, key, code);
198
+ return Qnil;
199
+ }
200
+
201
+ /*
202
+ * Adds library search paths
203
+ */
204
+ static VALUE
205
+ vm_jpath_add_m(int argc, const VALUE *argv, VALUE self)
206
+ {
207
+ int i;
208
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
209
+
210
+ for (i = 0; i < argc; ++i) {
211
+ VALUE jpath = argv[i];
212
+ FilePathValue(jpath);
213
+ jsonnet_jpath_add(vm->vm, StringValueCStr(jpath));
214
+ }
215
+ return Qnil;
216
+ }
217
+
218
+ static VALUE
219
+ vm_set_max_stack(VALUE self, VALUE val)
220
+ {
221
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
222
+ jsonnet_max_stack(vm->vm, NUM2UINT(val));
223
+ return Qnil;
224
+ }
225
+
226
+ static VALUE
227
+ vm_set_gc_min_objects(VALUE self, VALUE val)
228
+ {
229
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
230
+ jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
231
+ return Qnil;
232
+ }
233
+
234
+ static VALUE
235
+ vm_set_gc_growth_trigger(VALUE self, VALUE val)
236
+ {
237
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
238
+ jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
239
+ return Qnil;
240
+ }
241
+
242
+ /*
243
+ * Let #evaluate and #evaluate_file return a raw String instead of JSON-encoded string if val is
244
+ * true
245
+ * @param [Boolean] val
246
+ */
247
+ static VALUE
248
+ vm_set_string_output(VALUE self, VALUE val)
249
+ {
250
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
251
+ jsonnet_string_output(vm->vm, RTEST(val));
252
+ return Qnil;
253
+ }
254
+
255
+ static VALUE
256
+ vm_set_max_trace(VALUE self, VALUE val)
257
+ {
258
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
259
+ jsonnet_max_trace(vm->vm, NUM2UINT(val));
260
+ return Qnil;
261
+ }
262
+
263
+ static VALUE
264
+ vm_set_fmt_indent(VALUE self, VALUE val)
265
+ {
266
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
267
+ jsonnet_fmt_indent(vm->vm, NUM2INT(val));
268
+ return val;
269
+ }
270
+
271
+ static VALUE
272
+ vm_set_fmt_max_blank_lines(VALUE self, VALUE val)
273
+ {
274
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
275
+ jsonnet_fmt_max_blank_lines(vm->vm, NUM2INT(val));
276
+ return val;
277
+ }
278
+
279
+ static VALUE
280
+ vm_set_fmt_string(VALUE self, VALUE str)
281
+ {
282
+ const char *ptr;
283
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
284
+ StringValue(str);
285
+ if (RSTRING_LEN(str) != 1) {
286
+ rb_raise(rb_eArgError, "fmt_string must have a length of 1");
287
+ }
288
+ ptr = RSTRING_PTR(str);
289
+ switch (*ptr) {
290
+ case 'd':
291
+ case 's':
292
+ case 'l':
293
+ jsonnet_fmt_string(vm->vm, *ptr);
294
+ return str;
295
+ default:
296
+ rb_raise(rb_eArgError, "fmt_string only accepts 'd', 's', or 'l'");
297
+ }
298
+ }
299
+
300
+ static VALUE
301
+ vm_set_fmt_comment(VALUE self, VALUE str)
302
+ {
303
+ const char *ptr;
304
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
305
+ StringValue(str);
306
+ if (RSTRING_LEN(str) != 1) {
307
+ rb_raise(rb_eArgError, "fmt_comment must have a length of 1");
308
+ }
309
+ ptr = RSTRING_PTR(str);
310
+ switch (*ptr) {
311
+ case 'h':
312
+ case 's':
313
+ case 'l':
314
+ jsonnet_fmt_comment(vm->vm, *ptr);
315
+ return str;
316
+ default:
317
+ rb_raise(rb_eArgError, "fmt_comment only accepts 'h', 's', or 'l'");
318
+ }
319
+ }
320
+
321
+ static VALUE
322
+ vm_set_fmt_pad_arrays(VALUE self, VALUE val)
323
+ {
324
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
325
+ jsonnet_fmt_pad_objects(vm->vm, RTEST(val) ? 1 : 0);
326
+ return val;
327
+ }
328
+
329
+ static VALUE
330
+ vm_set_fmt_pad_objects(VALUE self, VALUE val)
331
+ {
332
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
333
+ jsonnet_fmt_pad_objects(vm->vm, RTEST(val) ? 1 : 0);
334
+ return val;
335
+ }
336
+
337
+ static VALUE
338
+ vm_set_fmt_pretty_field_names(VALUE self, VALUE val)
339
+ {
340
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
341
+ jsonnet_fmt_pretty_field_names(vm->vm, RTEST(val) ? 1 : 0);
342
+ return val;
343
+ }
344
+
345
+ static VALUE
346
+ vm_set_fmt_sort_imports(VALUE self, VALUE val)
347
+ {
348
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
349
+ jsonnet_fmt_sort_imports(vm->vm, RTEST(val) ? 1 : 0);
350
+ return val;
351
+ }
352
+
353
+ static VALUE
354
+ vm_fmt_file(VALUE self, VALUE fname, VALUE encoding)
355
+ {
356
+ int error;
357
+ char *result;
358
+ rb_encoding *const enc = rb_to_encoding(encoding);
359
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
360
+
361
+ FilePathValue(fname);
362
+ result = jsonnet_fmt_file(vm->vm, StringValueCStr(fname), &error);
363
+ if (error) {
364
+ raise_format_error(vm->vm, result, rb_enc_get(fname));
365
+ }
366
+ return str_new_json(vm->vm, result, enc);
367
+ }
368
+
369
+ static VALUE
370
+ vm_fmt_snippet(VALUE self, VALUE snippet, VALUE fname)
371
+ {
372
+ int error;
373
+ char *result;
374
+ struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
375
+
376
+ rb_encoding *enc = rubyjsonnet_assert_asciicompat(StringValue(snippet));
377
+ FilePathValue(fname);
378
+ result = jsonnet_fmt_snippet(vm->vm, StringValueCStr(fname), StringValueCStr(snippet), &error);
379
+ if (error) {
380
+ raise_format_error(vm->vm, result, rb_enc_get(fname));
381
+ }
382
+ return str_new_json(vm->vm, result, enc);
383
+ }
384
+
385
+ void
386
+ rubyjsonnet_init_vm(VALUE mJsonnet)
387
+ {
388
+ cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
389
+ rb_define_singleton_method(cVM, "new", vm_s_new, -1);
390
+ rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
391
+ rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
392
+ rb_define_private_method(cVM, "fmt_file", vm_fmt_file, 2);
393
+ rb_define_private_method(cVM, "fmt_snippet", vm_fmt_snippet, 2);
394
+ rb_define_method(cVM, "ext_var", vm_ext_var, 2);
395
+ rb_define_method(cVM, "ext_code", vm_ext_code, 2);
396
+ rb_define_method(cVM, "tla_var", vm_tla_var, 2);
397
+ rb_define_method(cVM, "tla_code", vm_tla_code, 2);
398
+ rb_define_method(cVM, "jpath_add", vm_jpath_add_m, -1);
399
+ rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
400
+ rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
401
+ rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
402
+ rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
403
+ rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
404
+ rb_define_method(cVM, "fmt_indent=", vm_set_fmt_indent, 1);
405
+ rb_define_method(cVM, "fmt_max_blank_lines=", vm_set_fmt_max_blank_lines, 1);
406
+ rb_define_method(cVM, "fmt_string=", vm_set_fmt_string, 1);
407
+ rb_define_method(cVM, "fmt_comment=", vm_set_fmt_comment, 1);
408
+ rb_define_method(cVM, "fmt_pad_arrays=", vm_set_fmt_pad_arrays, 1);
409
+ rb_define_method(cVM, "fmt_pad_objects=", vm_set_fmt_pad_objects, 1);
410
+ rb_define_method(cVM, "fmt_pretty_field_names=", vm_set_fmt_pretty_field_names, 1);
411
+ rb_define_method(cVM, "fmt_sort_imports=", vm_set_fmt_sort_imports, 1);
412
+
413
+ rb_define_const(mJsonnet, "STRING_STYLE_DOUBLE", rb_str_new_cstr("d"));
414
+ rb_define_const(mJsonnet, "STRING_STYLE_SINGLE", rb_str_new_cstr("s"));
415
+ rb_define_const(mJsonnet, "STRING_STYLE_LEAVE", rb_str_new_cstr("l"));
416
+ rb_define_const(mJsonnet, "COMMENT_STYLE_HASH", rb_str_new_cstr("h"));
417
+ rb_define_const(mJsonnet, "COMMENT_STYLE_SLASH", rb_str_new_cstr("s"));
418
+ rb_define_const(mJsonnet, "COMMENT_STYLE_LEAVE", rb_str_new_cstr("l"));
419
+
420
+ rubyjsonnet_init_callbacks(cVM);
421
+
422
+ eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
423
+ eFormatError = rb_define_class_under(mJsonnet, "FormatError", rb_eRuntimeError);
424
+ }
425
+
426
+ static void
427
+ raise_error(VALUE exception_class, struct JsonnetVm *vm, char *msg, rb_encoding *enc)
428
+ {
429
+ VALUE ex;
430
+ const int state = rubyjsonnet_jump_tag(msg);
431
+ if (state) {
432
+ /*
433
+ * This is not actually an exception but another type of long jump
434
+ * with the state, temporarily caught by rescue_callback().
435
+ */
436
+ jsonnet_realloc(vm, msg, 0);
437
+ rb_jump_tag(state);
438
+ }
439
+
440
+ ex = rb_exc_new3(exception_class, rb_enc_str_new_cstr(msg, enc));
441
+ jsonnet_realloc(vm, msg, 0);
442
+ rb_exc_raise(ex);
443
+ }
444
+
445
+ /**
446
+ * raises an EvaluationError whose message is \c msg.
447
+ * @param[in] vm a JsonnetVM
448
+ * @param[in] msg must be a NUL-terminated string returned by \c vm.
449
+ * @return never returns
450
+ * @throw EvaluationError
451
+ * @sa rescue_callback
452
+ */
453
+ static void
454
+ raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
455
+ {
456
+ raise_error(eEvaluationError, vm, msg, enc);
457
+ }
458
+
459
+ static void
460
+ raise_format_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
461
+ {
462
+ raise_error(eFormatError, vm, msg, enc);
463
+ }
464
+
465
+ /**
466
+ * Returns a String whose contents is equal to \c json.
467
+ * It automatically frees \c json just after constructing the return value.
468
+ *
469
+ * @param[in] vm a JsonnetVM
470
+ * @param[in] json must be a NUL-terminated string returned by \c vm.
471
+ * @return Ruby string equal to \c json.
472
+ */
473
+ static VALUE
474
+ str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
475
+ {
476
+ VALUE str = rb_enc_str_new_cstr(json, enc);
477
+ jsonnet_realloc(vm, json, 0);
478
+ return str;
479
+ }
480
+
481
+ /**
482
+ * Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
483
+ * and whose values are corresponding JSON values.
484
+ * It automatically frees \c json just after constructing the return value.
485
+ *
486
+ * @param[in] vm a JsonnetVM
487
+ * @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
488
+ * @return Hash
489
+ */
490
+ static VALUE
491
+ fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
492
+ {
493
+ VALUE fileset = rb_hash_new();
494
+ char *ptr, *json;
495
+ for (ptr = buf; *ptr; ptr = json + strlen(json) + 1) {
496
+ json = ptr + strlen(ptr) + 1;
497
+ if (!*json) {
498
+ VALUE ex = rb_exc_new3(eEvaluationError,
499
+ rb_enc_sprintf(enc, "output file %s without body", ptr));
500
+ jsonnet_realloc(vm, buf, 0);
501
+ rb_exc_raise(ex);
502
+ }
503
+
504
+ rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
505
+ }
506
+ jsonnet_realloc(vm, buf, 0);
507
+ return fileset;
508
+ }