jsonnet 0.1.1 → 0.2.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.
- checksums.yaml +4 -4
- data/.clang-format +11 -0
- data/ext/jsonnet/callbacks.c +241 -0
- data/ext/jsonnet/helpers.c +74 -0
- data/ext/jsonnet/jsonnet.c +4 -348
- data/ext/jsonnet/jsonnet_values.c +206 -0
- data/ext/jsonnet/ruby_jsonnet.h +39 -0
- data/ext/jsonnet/vm.c +351 -0
- data/lib/jsonnet/version.rb +1 -1
- data/lib/jsonnet/vm.rb +36 -1
- data/test/fixtures/jpath.libsonnet +3 -0
- data/test/test_vm.rb +218 -1
- metadata +10 -2
@@ -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_ */
|
data/ext/jsonnet/vm.c
ADDED
@@ -0,0 +1,351 @@
|
|
1
|
+
#include <libjsonnet.h>
|
2
|
+
#include <ruby/ruby.h>
|
3
|
+
#include <ruby/intern.h>
|
4
|
+
|
5
|
+
#include "ruby_jsonnet.h"
|
6
|
+
|
7
|
+
/*
|
8
|
+
* defines the core part of Jsonnet::VM
|
9
|
+
*/
|
10
|
+
|
11
|
+
/*
|
12
|
+
* Jsonnet evaluator
|
13
|
+
*
|
14
|
+
* call-seq:
|
15
|
+
* Jsonnet::VM
|
16
|
+
*/
|
17
|
+
static VALUE cVM;
|
18
|
+
|
19
|
+
/*
|
20
|
+
* Raised on evaluation errors in a Jsonnet VM.
|
21
|
+
*/
|
22
|
+
static VALUE eEvaluationError;
|
23
|
+
|
24
|
+
static void raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc);
|
25
|
+
static VALUE str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc);
|
26
|
+
static VALUE fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc);
|
27
|
+
|
28
|
+
static void vm_free(void *ptr);
|
29
|
+
static void vm_mark(void *ptr);
|
30
|
+
|
31
|
+
const rb_data_type_t jsonnet_vm_type = {
|
32
|
+
"JsonnetVm",
|
33
|
+
{
|
34
|
+
/* dmark = */ vm_mark,
|
35
|
+
/* dfree = */ vm_free,
|
36
|
+
/* dsize = */ 0,
|
37
|
+
},
|
38
|
+
/* parent = */ 0,
|
39
|
+
/* data = */ 0,
|
40
|
+
/* flags = */ RUBY_TYPED_FREE_IMMEDIATELY,
|
41
|
+
};
|
42
|
+
|
43
|
+
struct jsonnet_vm_wrap *
|
44
|
+
rubyjsonnet_obj_to_vm(VALUE wrap)
|
45
|
+
{
|
46
|
+
struct jsonnet_vm_wrap *vm;
|
47
|
+
TypedData_Get_Struct(wrap, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
48
|
+
|
49
|
+
return vm;
|
50
|
+
}
|
51
|
+
|
52
|
+
static VALUE
|
53
|
+
vm_s_new(int argc, const VALUE *argv, VALUE klass)
|
54
|
+
{
|
55
|
+
struct jsonnet_vm_wrap *vm;
|
56
|
+
VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
57
|
+
vm->vm = jsonnet_make();
|
58
|
+
vm->import_callback = Qnil;
|
59
|
+
vm->native_callbacks.len = 0;
|
60
|
+
vm->native_callbacks.contexts = NULL;
|
61
|
+
|
62
|
+
rb_obj_call_init(self, argc, argv);
|
63
|
+
return self;
|
64
|
+
}
|
65
|
+
|
66
|
+
static void
|
67
|
+
vm_free(void *ptr)
|
68
|
+
{
|
69
|
+
int i;
|
70
|
+
struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
|
71
|
+
jsonnet_destroy(vm->vm);
|
72
|
+
|
73
|
+
for (i = 0; i < vm->native_callbacks.len; ++i) {
|
74
|
+
struct native_callback_ctx *ctx = vm->native_callbacks.contexts[i];
|
75
|
+
RB_REALLOC_N(ctx, struct native_callback_ctx, 0);
|
76
|
+
}
|
77
|
+
RB_REALLOC_N(vm->native_callbacks.contexts, struct native_callback_ctx *, 0);
|
78
|
+
|
79
|
+
RB_REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
|
80
|
+
}
|
81
|
+
|
82
|
+
static void
|
83
|
+
vm_mark(void *ptr)
|
84
|
+
{
|
85
|
+
int i;
|
86
|
+
struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap *)ptr;
|
87
|
+
|
88
|
+
rb_gc_mark(vm->import_callback);
|
89
|
+
for (i = 0; i < vm->native_callbacks.len; ++i) {
|
90
|
+
rb_gc_mark(vm->native_callbacks.contexts[i]->callback);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
|
96
|
+
{
|
97
|
+
int error;
|
98
|
+
char *result;
|
99
|
+
rb_encoding *const enc = rb_to_encoding(encoding);
|
100
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
101
|
+
|
102
|
+
FilePathValue(fname);
|
103
|
+
if (RTEST(multi_p)) {
|
104
|
+
result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
|
105
|
+
} else {
|
106
|
+
result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
|
107
|
+
}
|
108
|
+
|
109
|
+
if (error) {
|
110
|
+
raise_eval_error(vm->vm, result, rb_enc_get(fname));
|
111
|
+
}
|
112
|
+
return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
|
113
|
+
}
|
114
|
+
|
115
|
+
static VALUE
|
116
|
+
vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
|
117
|
+
{
|
118
|
+
int error;
|
119
|
+
char *result;
|
120
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
121
|
+
|
122
|
+
rb_encoding *enc = rubyjsonnet_assert_asciicompat(StringValue(snippet));
|
123
|
+
FilePathValue(fname);
|
124
|
+
if (RTEST(multi_p)) {
|
125
|
+
result = jsonnet_evaluate_snippet_multi(vm->vm, StringValueCStr(fname),
|
126
|
+
StringValueCStr(snippet), &error);
|
127
|
+
} else {
|
128
|
+
result = jsonnet_evaluate_snippet(vm->vm, StringValueCStr(fname), StringValueCStr(snippet),
|
129
|
+
&error);
|
130
|
+
}
|
131
|
+
|
132
|
+
if (error) {
|
133
|
+
raise_eval_error(vm->vm, result, rb_enc_get(fname));
|
134
|
+
}
|
135
|
+
return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
|
136
|
+
}
|
137
|
+
|
138
|
+
#define vm_bind_variable(type, self, key, val) \
|
139
|
+
do { \
|
140
|
+
struct jsonnet_vm_wrap *vm; \
|
141
|
+
\
|
142
|
+
rubyjsonnet_assert_asciicompat(StringValue(key)); \
|
143
|
+
rubyjsonnet_assert_asciicompat(StringValue(val)); \
|
144
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm); \
|
145
|
+
jsonnet_##type(vm->vm, StringValueCStr(key), StringValueCStr(val)); \
|
146
|
+
} while (0)
|
147
|
+
|
148
|
+
/*
|
149
|
+
* Binds an external variable to a value.
|
150
|
+
* @param [String] key name of the variable
|
151
|
+
* @param [String] val the value
|
152
|
+
*/
|
153
|
+
static VALUE
|
154
|
+
vm_ext_var(VALUE self, VALUE key, VALUE val)
|
155
|
+
{
|
156
|
+
vm_bind_variable(ext_var, self, key, val);
|
157
|
+
return Qnil;
|
158
|
+
}
|
159
|
+
|
160
|
+
/*
|
161
|
+
* Binds an external variable to a code fragment.
|
162
|
+
* @param [String] key name of the variable
|
163
|
+
* @param [String] code Jsonnet expression
|
164
|
+
*/
|
165
|
+
static VALUE
|
166
|
+
vm_ext_code(VALUE self, VALUE key, VALUE code)
|
167
|
+
{
|
168
|
+
vm_bind_variable(ext_code, self, key, code);
|
169
|
+
return Qnil;
|
170
|
+
}
|
171
|
+
|
172
|
+
/*
|
173
|
+
* Binds a top-level argument to a value.
|
174
|
+
* @param [String] key name of the variable
|
175
|
+
* @param [String] val the value
|
176
|
+
*/
|
177
|
+
static VALUE
|
178
|
+
vm_tla_var(VALUE self, VALUE key, VALUE val)
|
179
|
+
{
|
180
|
+
vm_bind_variable(tla_var, self, key, val);
|
181
|
+
return Qnil;
|
182
|
+
}
|
183
|
+
|
184
|
+
/*
|
185
|
+
* Binds a top-level argument to a code fragment.
|
186
|
+
* @param [String] key name of the variable
|
187
|
+
* @param [String] code Jsonnet expression
|
188
|
+
*/
|
189
|
+
static VALUE
|
190
|
+
vm_tla_code(VALUE self, VALUE key, VALUE code)
|
191
|
+
{
|
192
|
+
vm_bind_variable(tla_code, self, key, code);
|
193
|
+
return Qnil;
|
194
|
+
}
|
195
|
+
|
196
|
+
/*
|
197
|
+
* Adds library search paths
|
198
|
+
*/
|
199
|
+
static VALUE
|
200
|
+
vm_jpath_add_m(int argc, const VALUE *argv, VALUE self)
|
201
|
+
{
|
202
|
+
int i;
|
203
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
204
|
+
|
205
|
+
for (i = 0; i < argc; ++i) {
|
206
|
+
VALUE jpath = argv[i];
|
207
|
+
FilePathValue(jpath);
|
208
|
+
jsonnet_jpath_add(vm->vm, StringValueCStr(jpath));
|
209
|
+
}
|
210
|
+
return Qnil;
|
211
|
+
}
|
212
|
+
|
213
|
+
static VALUE
|
214
|
+
vm_set_max_stack(VALUE self, VALUE val)
|
215
|
+
{
|
216
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
217
|
+
jsonnet_max_stack(vm->vm, NUM2UINT(val));
|
218
|
+
return Qnil;
|
219
|
+
}
|
220
|
+
|
221
|
+
static VALUE
|
222
|
+
vm_set_gc_min_objects(VALUE self, VALUE val)
|
223
|
+
{
|
224
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
225
|
+
jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
|
226
|
+
return Qnil;
|
227
|
+
}
|
228
|
+
|
229
|
+
static VALUE
|
230
|
+
vm_set_gc_growth_trigger(VALUE self, VALUE val)
|
231
|
+
{
|
232
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
233
|
+
jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
|
234
|
+
return Qnil;
|
235
|
+
}
|
236
|
+
|
237
|
+
/*
|
238
|
+
* Let #evaluate and #evaluate_file return a raw String instead of JSON-encoded string if val is
|
239
|
+
* true
|
240
|
+
* @param [Boolean] val
|
241
|
+
*/
|
242
|
+
static VALUE
|
243
|
+
vm_set_string_output(VALUE self, VALUE val)
|
244
|
+
{
|
245
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
246
|
+
jsonnet_string_output(vm->vm, RTEST(val));
|
247
|
+
return Qnil;
|
248
|
+
}
|
249
|
+
|
250
|
+
static VALUE
|
251
|
+
vm_set_max_trace(VALUE self, VALUE val)
|
252
|
+
{
|
253
|
+
struct jsonnet_vm_wrap *vm = rubyjsonnet_obj_to_vm(self);
|
254
|
+
jsonnet_max_trace(vm->vm, NUM2UINT(val));
|
255
|
+
return Qnil;
|
256
|
+
}
|
257
|
+
|
258
|
+
void
|
259
|
+
rubyjsonnet_init_vm(VALUE mJsonnet)
|
260
|
+
{
|
261
|
+
cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
|
262
|
+
rb_define_singleton_method(cVM, "new", vm_s_new, -1);
|
263
|
+
rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
|
264
|
+
rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
|
265
|
+
rb_define_method(cVM, "ext_var", vm_ext_var, 2);
|
266
|
+
rb_define_method(cVM, "ext_code", vm_ext_code, 2);
|
267
|
+
rb_define_method(cVM, "tla_var", vm_tla_var, 2);
|
268
|
+
rb_define_method(cVM, "tla_code", vm_tla_code, 2);
|
269
|
+
rb_define_method(cVM, "jpath_add", vm_jpath_add_m, -1);
|
270
|
+
rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
|
271
|
+
rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
|
272
|
+
rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
|
273
|
+
rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
|
274
|
+
rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
|
275
|
+
|
276
|
+
rubyjsonnet_init_callbacks(cVM);
|
277
|
+
|
278
|
+
eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
|
279
|
+
}
|
280
|
+
|
281
|
+
/**
|
282
|
+
* raises an EvaluationError whose message is \c msg.
|
283
|
+
* @param[in] vm a JsonnetVM
|
284
|
+
* @param[in] msg must be a NUL-terminated string returned by \c vm.
|
285
|
+
* @return never returns
|
286
|
+
* @throw EvaluationError
|
287
|
+
* @sa rescue_callback
|
288
|
+
*/
|
289
|
+
static void
|
290
|
+
raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
|
291
|
+
{
|
292
|
+
VALUE ex;
|
293
|
+
const int state = rubyjsonnet_jump_tag(msg);
|
294
|
+
if (state) {
|
295
|
+
/*
|
296
|
+
* This is not actually an exception but another type of long jump
|
297
|
+
* with the state, temporarily caught by rescue_callback().
|
298
|
+
*/
|
299
|
+
jsonnet_realloc(vm, msg, 0);
|
300
|
+
rb_jump_tag(state);
|
301
|
+
}
|
302
|
+
|
303
|
+
ex = rb_exc_new3(eEvaluationError, rb_enc_str_new_cstr(msg, enc));
|
304
|
+
jsonnet_realloc(vm, msg, 0);
|
305
|
+
rb_exc_raise(ex);
|
306
|
+
}
|
307
|
+
|
308
|
+
/**
|
309
|
+
* Returns a String whose contents is equal to \c json.
|
310
|
+
* It automatically frees \c json just after constructing the return value.
|
311
|
+
*
|
312
|
+
* @param[in] vm a JsonnetVM
|
313
|
+
* @param[in] json must be a NUL-terminated string returned by \c vm.
|
314
|
+
* @return Ruby string equal to \c json.
|
315
|
+
*/
|
316
|
+
static VALUE
|
317
|
+
str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
|
318
|
+
{
|
319
|
+
VALUE str = rb_enc_str_new_cstr(json, enc);
|
320
|
+
jsonnet_realloc(vm, json, 0);
|
321
|
+
return str;
|
322
|
+
}
|
323
|
+
|
324
|
+
/**
|
325
|
+
* Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
|
326
|
+
* and whose values are corresponding JSON values.
|
327
|
+
* It automatically frees \c json just after constructing the return value.
|
328
|
+
*
|
329
|
+
* @param[in] vm a JsonnetVM
|
330
|
+
* @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
|
331
|
+
* @return Hash
|
332
|
+
*/
|
333
|
+
static VALUE
|
334
|
+
fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
|
335
|
+
{
|
336
|
+
VALUE fileset = rb_hash_new();
|
337
|
+
char *ptr, *json;
|
338
|
+
for (ptr = buf; *ptr; ptr = json + strlen(json) + 1) {
|
339
|
+
json = ptr + strlen(ptr) + 1;
|
340
|
+
if (!*json) {
|
341
|
+
VALUE ex = rb_exc_new3(eEvaluationError,
|
342
|
+
rb_enc_sprintf(enc, "output file %s without body", ptr));
|
343
|
+
jsonnet_realloc(vm, buf, 0);
|
344
|
+
rb_exc_raise(ex);
|
345
|
+
}
|
346
|
+
|
347
|
+
rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
|
348
|
+
}
|
349
|
+
jsonnet_realloc(vm, buf, 0);
|
350
|
+
return fileset;
|
351
|
+
}
|