Skip to content

Commit

Permalink
Added native functions, fix google#108
Browse files Browse the repository at this point in the history
  • Loading branch information
sparkprime committed May 28, 2016
1 parent 1c3cf2a commit 4876d97
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 11 deletions.
3 changes: 2 additions & 1 deletion core/desugarer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct BuiltinDecl {
std::vector<String> params;
};

static unsigned long max_builtin = 24;
static unsigned long max_builtin = 25;
BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
{
switch (builtin) {
Expand Down Expand Up @@ -60,6 +60,7 @@ BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
case 22: return {U"modulo", {U"a", U"b"}};
case 23: return {U"extVar", {U"x"}};
case 24: return {U"primitiveEquals", {U"a", U"b"}};
case 25: return {U"native", {U"name"}};
default:
std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl;
std::abort();
Expand Down
8 changes: 5 additions & 3 deletions core/libjsonnet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,19 @@ static char *from_string(JsonnetVm* vm, const std::string &v)
static char *default_import_callback(void *ctx, const char *dir, const char *file,
char **found_here_cptr, int *success);

const char *jsonnet_json_extract_string(struct JsonnetJsonValue *v)
const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonValue *v)
{
(void) vm;
if (v->kind != JsonnetJsonValue::STRING)
return nullptr;
return v->string.c_str();
}

/** Convert the given UTF8 string to a JsonnetJsonValue.
*/
JsonnetJsonValue *jsonnet_json_make_string(const char *v)
JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v)
{
(void) vm;
JsonnetJsonValue *r = new JsonnetJsonValue();
r->kind = JsonnetJsonValue::STRING;
r->string = v;
Expand Down Expand Up @@ -235,7 +237,7 @@ void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNati
void *ctx, const char * const *params)
{
std::vector<std::string> params2;
for (; params != nullptr; params++)
for (; *params != nullptr; params++)
params2.push_back(*params);
vm->nativeCallbacks[name] = VmNativeCallback {cb, ctx, params2};
}
Expand Down
21 changes: 21 additions & 0 deletions core/libjsonnet_test_snippet.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,40 @@ limitations under the License.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <libjsonnet.h>

struct JsonnetJsonValue *concat(void *ctx, const struct JsonnetJsonValue * const *argv, int *succ)
{
struct JsonnetVm *vm = (struct JsonnetVm *)ctx;
const char *a = jsonnet_json_extract_string(vm, argv[0]);
const char *b = jsonnet_json_extract_string(vm, argv[1]);
if (a == NULL || b == NULL) {
struct JsonnetJsonValue *r = jsonnet_json_make_string(vm, "Bad params.");
*succ = 0;
return r;
}
char *str = malloc(strlen(a) + strlen(b) + 1);
sprintf(str, "%s%s", a, b);
struct JsonnetJsonValue *r = jsonnet_json_make_string(vm, str);
free(str);
*succ = 1;
return r;
}

int main(int argc, const char **argv)
{
int error;
char *output;
struct JsonnetVm *vm;
const char *params[] = {"a", "b", NULL};
if (argc != 2) {
fprintf(stderr, "libjsonnet_test_snippet <string>\n");
return EXIT_FAILURE;
}
vm = jsonnet_make();
jsonnet_native_callback(vm, "concat", concat, vm, params);
output = jsonnet_evaluate_snippet(vm, "snippet", argv[1], &error);
if (error) {
fprintf(stderr, "%s", output);
Expand Down
25 changes: 22 additions & 3 deletions core/vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@ class Interpreter {
builtins["modulo"] = &Interpreter::builtinModulo;
builtins["extVar"] = &Interpreter::builtinExtVar;
builtins["primitiveEquals"] = &Interpreter::builtinPrimitiveEquals;
builtins["native"] = &Interpreter::builtinNative;
}

/** Clean up the heap, stack, stash, and builtin function ASTs. */
Expand Down Expand Up @@ -1243,6 +1244,22 @@ class Interpreter {
return nullptr;
}

const AST *builtinNative(const LocationRange &loc, const std::vector<Value> &args)
{
validateBuiltinArgs(loc, "native", args, {Value::STRING});

std::string builtin_name = encode_utf8(static_cast<HeapString*>(args[0].v.h)->value);

VmNativeCallbackMap::const_iterator nit = nativeCallbacks.find(builtin_name);
if (nit == nativeCallbacks.end()) {
throw makeError(loc, "Unrecognized native function name: " + builtin_name);
}

const VmNativeCallback &cb = nit->second;
scratch = makeNativeBuiltin(builtin_name, cb.params);
return nullptr;
}


String toString(const LocationRange &loc)
{
Expand Down Expand Up @@ -1966,14 +1983,14 @@ class Interpreter {
encode_utf8(static_cast<HeapString*>(arg.v.h)->value)
});
}
std::vector<JsonnetJsonValue*> args3;
std::vector<const JsonnetJsonValue*> args3;
for (size_t i = 0; i < args2.size() ; ++i) {
args3.push_back(&args2[i]);
}
if (nit != nativeCallbacks.end()) {
const VmNativeCallback &cb = nit->second;
int succ;
JsonnetJsonValue *r = cb.cb(cb.ctx, args3.size(), &args3[0], &succ);
JsonnetJsonValue *r = cb.cb(cb.ctx, &args3[0], &succ);
if (succ) {
// TODO(dcunnin): Support more than just strings.
if (r->kind != JsonnetJsonValue::STRING) {
Expand All @@ -1982,7 +1999,9 @@ class Interpreter {
"Native extensions can only return a string.");
}
std::string rs = r->string;
delete r;
scratch = makeString(decode_utf8(rs));
break;
} else {
if (r->kind != JsonnetJsonValue::STRING) {
delete r;
Expand All @@ -1997,7 +2016,7 @@ class Interpreter {
}

throw makeError(ast.location,
"Unrecognized native function name: " + builtin_name);
"Unrecognized builtin name: " + builtin_name);
} else {
HeapThunk *th = f.thunks[f.elementId++];
if (!th->filled) {
Expand Down
8 changes: 4 additions & 4 deletions include/libjsonnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ struct JsonnetJsonValue;

/** If the value is a string, return it as UTF8 otherwise return NULL.
*/
const char *jsonnet_json_extract_string(struct JsonnetJsonValue *v);
const char *jsonnet_json_extract_string(struct JsonnetVm *vm, const struct JsonnetJsonValue *v);

/** Convert the given UTF8 string to a JsonnetJsonValue.
*/
struct JsonnetJsonValue *jsonnet_json_make_string(const char *v);
struct JsonnetJsonValue *jsonnet_json_make_string(struct JsonnetVm *vm, const char *v);

/** Callback to provide native extensions to Jsonnet.
*
Expand All @@ -92,8 +92,8 @@ struct JsonnetJsonValue *jsonnet_json_make_string(const char *v);
* \param success Set this byref param to 1 to indicate success and 0 for failure.
* \returns The content of the imported file, or an error message.
*/
typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx, size_t argc,
struct JsonnetJsonValue **argv,
typedef struct JsonnetJsonValue *JsonnetNativeCallback(void *ctx,
const struct JsonnetJsonValue * const *argv,
int *success);

/** Allocate, resize, or free a buffer. This will abort if the memory cannot be allocated. It will
Expand Down
17 changes: 17 additions & 0 deletions test_suite/error.native_not_found.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
Copyright 2015 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

std.native("non_existent_native")
2 changes: 2 additions & 0 deletions test_suite/error.native_not_found.jsonnet.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
RUNTIME ERROR: Unrecognized native function name: non_existent_native
error.native_not_found.jsonnet:17:1-33

0 comments on commit 4876d97

Please sign in to comment.