ext/jsonnet/jsonnet.c in jsonnet-0.1.1 vs ext/jsonnet/jsonnet.c in jsonnet-0.2.0
- old
+ new
@@ -1,131 +1,12 @@
-#include <string.h>
+#include <libjsonnet.h>
#include <ruby/ruby.h>
-#include <ruby/intern.h>
#include <ruby/encoding.h>
-#include <libjsonnet.h>
-static ID id_call;
-static ID id_message;
+#include "ruby_jsonnet.h"
/*
- * Jsonnet evaluator
- */
-static VALUE cVM;
-static VALUE eEvaluationError;
-/**
- * Indicates that the encoding of the given string is not allowed by
- * the C++ implementation of Jsonnet.
- */
-static VALUE eUnsupportedEncodingError;
-
-struct jsonnet_vm_wrap {
- struct JsonnetVm *vm;
- VALUE callback;
-};
-
-static void vm_free(void *ptr);
-static void vm_mark(void *ptr);
-
-static const rb_data_type_t jsonnet_vm_type = {
- "JsonnetVm",
- {
- /* dmark = */ vm_mark,
- /* dfree = */ vm_free,
- /* dsize = */ 0,
- },
- /* parent = */ 0,
- /* data = */ 0,
- /* flags = */ RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-/**
- * raises an EvaluationError whose message is \c msg.
- * @param[in] vm a JsonnetVM
- * @param[in] msg must be a NUL-terminated string returned by \c vm.
- * @return never returns
- * @throw EvaluationError
- */
-static void
-raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
-{
- VALUE ex = rb_exc_new3(eEvaluationError, rb_enc_str_new_cstr(msg, enc));
- jsonnet_realloc(vm, msg, 0);
- rb_exc_raise(ex);
-}
-
-/**
- * Returns a String whose contents is equal to \c json.
- * It automatically frees \c json just after constructing the return value.
- *
- * @param[in] vm a JsonnetVM
- * @param[in] json must be a NUL-terminated string returned by \c vm.
- * @return Ruby string equal to \c json.
- */
-static VALUE
-str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
-{
- VALUE str = rb_enc_str_new_cstr(json, enc);
- jsonnet_realloc(vm, json, 0);
- return str;
-}
-
-/**
- * Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
- * and whose values are corresponding JSON values.
- * It automatically frees \c json just after constructing the return value.
- *
- * @param[in] vm a JsonnetVM
- * @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
- * @return Hash
- */
-static VALUE
-fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
-{
- VALUE fileset = rb_hash_new();
- char *ptr, *json;
- for (ptr = buf; *ptr; ptr = json + strlen(json)+1) {
- json = ptr + strlen(ptr) + 1;
- if (!*json) {
- VALUE ex = rb_exc_new3(
- eEvaluationError,
- rb_enc_sprintf(enc, "output file %s without body", ptr));
- jsonnet_realloc(vm, buf, 0);
- rb_exc_raise(ex);
- }
-
- rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
- }
- jsonnet_realloc(vm, buf, 0);
- return fileset;
-}
-
-/**
- * Allocates a C string whose content is equal to \c str with jsonnet_realloc.
- */
-static char *
-str_jsonnet_cstr(struct JsonnetVm *vm, VALUE str)
-{
- const char *const cstr = StringValueCStr(str);
- char *const buf = jsonnet_realloc(vm, NULL, strlen(cstr));
- strcpy(buf, cstr);
- return buf;
-}
-
-static rb_encoding *
-enc_assert_asciicompat(VALUE str) {
- rb_encoding *enc = rb_enc_get(str);
- if (!rb_enc_asciicompat(enc)) {
- rb_raise(
- eUnsupportedEncodingError,
- "jsonnet encoding must be ASCII-compatible but got %s",
- rb_enc_name(enc));
- }
- return enc;
-}
-
-/*
* call-seq:
* Jsonnet.version -> String
*
* Returns the version of the underlying C++ implementation of Jsonnet.
*/
@@ -133,239 +14,14 @@
jw_s_version(VALUE mod)
{
return rb_usascii_str_new_cstr(jsonnet_version());
}
-static VALUE
-vm_s_new(int argc, const VALUE *argv, VALUE klass)
-{
- struct jsonnet_vm_wrap *vm;
- VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- vm->vm = jsonnet_make();
- vm->callback = Qnil;
- rb_obj_call_init(self, argc, argv);
- return self;
-}
-
-static void
-vm_free(void *ptr)
-{
- struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap*)ptr;
- jsonnet_destroy(vm->vm);
- REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
-}
-
-static void
-vm_mark(void *ptr)
-{
- struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap*)ptr;
- rb_gc_mark(vm->callback);
-}
-
-static VALUE
-vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
-{
- struct jsonnet_vm_wrap *vm;
- int error;
- char *result;
- rb_encoding *const enc = rb_to_encoding(encoding);
-
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- FilePathValue(fname);
- if (RTEST(multi_p)) {
- result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
- }
- else {
- result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
- }
-
- if (error) {
- raise_eval_error(vm->vm, result, rb_enc_get(fname));
- }
- return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
-}
-
-static VALUE
-vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
-{
- struct jsonnet_vm_wrap *vm;
- int error;
- char *result;
-
- rb_encoding *enc = enc_assert_asciicompat(StringValue(snippet));
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- FilePathValue(fname);
- if (RTEST(multi_p)) {
- result = jsonnet_evaluate_snippet_multi(
- vm->vm,
- StringValueCStr(fname), StringValueCStr(snippet), &error);
- }
- else {
- result = jsonnet_evaluate_snippet(
- vm->vm,
- StringValueCStr(fname), StringValueCStr(snippet), &error);
- }
-
- if (error) {
- raise_eval_error(vm->vm, result, rb_enc_get(fname));
- }
- return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
-}
-
-static VALUE
-import_callback_thunk0(VALUE args)
-{
- VALUE callback = rb_ary_entry(args, 0);
- return rb_funcall(callback, id_call, 2, rb_ary_entry(args, 1), rb_ary_entry(args, 2));
-}
-
-static char *
-import_callback_thunk(void *ctx, const char *base, const char *rel, char **found_here, int *success)
-{
- struct jsonnet_vm_wrap *const vm = (struct jsonnet_vm_wrap*)ctx;
- int state;
- VALUE result, args;
-
- args = rb_ary_tmp_new(3);
- rb_ary_push(args, vm->callback);
- rb_ary_push(args, rb_enc_str_new_cstr(base, rb_filesystem_encoding()));
- rb_ary_push(args, rb_enc_str_new_cstr(rel, rb_filesystem_encoding()));
- result = rb_protect(import_callback_thunk0, args, &state);
-
- if (state) {
- VALUE err = rb_errinfo();
- VALUE msg, name;
-
- rb_set_errinfo(Qnil);
- name = rb_class_name(rb_obj_class(err));
- msg = rb_funcall(err, id_message, 0);
- if (rb_str_strlen(name)) {
- if (rb_str_strlen(msg)) {
- msg = rb_str_concat(rb_str_cat_cstr(name, " : "), msg);
- } else {
- msg = name;
- }
- } else if (!rb_str_strlen(msg)) {
- msg = rb_sprintf("cannot import %s from %s", rel, base);
- }
- *success = 0;
- return str_jsonnet_cstr(vm->vm, msg);
- }
-
- result = rb_Array(result);
- *success = 1;
- *found_here = str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 1));
- return str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 0));
-}
-
-/**
- * Sets a custom way to resolve "import" expression.
- * @param [#call] callback receives two parameters and returns two values.
- * The first parameter "base" is a base directory to resolve
- * "rel" from.
- * The second parameter "rel" is an absolute or a relative
- * path to the file to import.
- * The first return value is the content of the imported file.
- * The second return value is the resolved path of the imported file.
- */
-static VALUE
-vm_set_import_callback(VALUE self, VALUE callback)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
-
- vm->callback = callback;
- jsonnet_import_callback(vm->vm, import_callback_thunk, vm);
- return callback;
-}
-
-/*
- * Binds an external variable to a value.
- * @param [String] key name of the variable
- * @param [String] val the value
- */
-static VALUE
-vm_ext_var(VALUE self, VALUE key, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
-
- enc_assert_asciicompat(StringValue(key));
- enc_assert_asciicompat(StringValue(val));
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_ext_var(vm->vm, StringValueCStr(key), StringValueCStr(val));
- return Qnil;
-}
-
-static VALUE
-vm_set_max_stack(VALUE self, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_max_stack(vm->vm, NUM2UINT(val));
- return Qnil;
-}
-
-static VALUE
-vm_set_gc_min_objects(VALUE self, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
- return Qnil;
-}
-
-static VALUE
-vm_set_gc_growth_trigger(VALUE self, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
- return Qnil;
-}
-
-/*
- * Let #evaluate and #evaluate_file return a raw String instead of JSON-encoded string if val is true
- * @param [Boolean] val
- */
-static VALUE
-vm_set_string_output(VALUE self, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_string_output(vm->vm, RTEST(val));
- return Qnil;
-}
-
-static VALUE
-vm_set_max_trace(VALUE self, VALUE val)
-{
- struct jsonnet_vm_wrap *vm;
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
- jsonnet_max_trace(vm->vm, NUM2UINT(val));
- return Qnil;
-}
-
void
Init_jsonnet_wrap(void)
{
- id_call = rb_intern("call");
- id_message = rb_intern("message");
-
VALUE mJsonnet = rb_define_module("Jsonnet");
rb_define_singleton_method(mJsonnet, "libversion", jw_s_version, 0);
- cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
- rb_define_singleton_method(cVM, "new", vm_s_new, -1);
- rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
- rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
- rb_define_method(cVM, "ext_var", vm_ext_var, 2);
- rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
- rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
- rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
- rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
- rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
- rb_define_method(cVM, "import_callback=", vm_set_import_callback, 1);
-
- eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
- eUnsupportedEncodingError =
- rb_define_class_under(mJsonnet, "UnsupportedEncodingError", rb_eEncodingError);
+ rubyjsonnet_init_helpers(mJsonnet);
+ rubyjsonnet_init_vm(mJsonnet);
}