Skip to content

Commit 49ea2f4

Browse files
committed
Merge pull request #198 from sparkprime/extensions
Native Extensions
2 parents c292727 + bcbcdf1 commit 49ea2f4

17 files changed

+966
-427
lines changed

core/ast.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,11 @@ struct Binary : public AST {
308308
* interpreter.
309309
*/
310310
struct BuiltinFunction : public AST {
311-
unsigned long id;
311+
std::string name;
312312
Identifiers params;
313-
BuiltinFunction(const LocationRange &lr, unsigned long id,
313+
BuiltinFunction(const LocationRange &lr, const std::string &name,
314314
const Identifiers &params)
315-
: AST(lr, AST_BUILTIN_FUNCTION, Fodder{}), id(id), params(params)
315+
: AST(lr, AST_BUILTIN_FUNCTION, Fodder{}), name(name), params(params)
316316
{ }
317317
};
318318

core/desugarer.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ static const Fodder EF; // Empty fodder.
2626

2727
static const LocationRange E; // Empty.
2828

29-
static unsigned long max_builtin = 24;
29+
struct BuiltinDecl {
30+
String name;
31+
std::vector<String> params;
32+
};
33+
34+
static unsigned long max_builtin = 25;
3035
BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
3136
{
3237
switch (builtin) {
@@ -55,6 +60,7 @@ BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
5560
case 22: return {U"modulo", {U"a", U"b"}};
5661
case 23: return {U"extVar", {U"x"}};
5762
case 24: return {U"primitiveEquals", {U"a", U"b"}};
63+
case 25: return {U"native", {U"name"}};
5864
default:
5965
std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl;
6066
std::abort();
@@ -761,7 +767,7 @@ class Desugarer {
761767
fields.emplace_back(
762768
ObjectField::HIDDEN,
763769
str(decl.name),
764-
make<BuiltinFunction>(E, c, params));
770+
make<BuiltinFunction>(E, encode_utf8(decl.name), params));
765771
}
766772
fields.emplace_back(
767773
ObjectField::HIDDEN,

core/formatter.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ class Unparser {
343343
unparse(ast->right, true);
344344

345345
} else if (auto *ast = dynamic_cast<const BuiltinFunction*>(ast_)) {
346-
o << "/* builtin " << ast->id << " */ null";
346+
o << "/* builtin " << ast->name << " */ null";
347347

348348
} else if (auto *ast = dynamic_cast<const Conditional*>(ast_)) {
349349
o << "if";
@@ -1724,10 +1724,8 @@ class FixIndentation {
17241724
expr(ast->right, new_indent, true);
17251725

17261726
} else if (auto *ast = dynamic_cast<BuiltinFunction*>(ast_)) {
1727-
std::stringstream ss;
1728-
ss << ast->id;
17291727
column += 11; // "/* builtin "
1730-
column += ss.str().length();
1728+
column += ast->name.length();
17311729
column += 8; // " */ null"
17321730

17331731
} else if (auto *ast = dynamic_cast<Conditional*>(ast_)) {

core/json.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
Copyright 2015 Google Inc. All rights reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#ifndef JSONNET_JSON_H
18+
#define JSONNET_JSON_H
19+
20+
#include <string>
21+
22+
#include <libjsonnet.h>
23+
24+
struct JsonnetJsonValue {
25+
enum Kind {
26+
STRING
27+
};
28+
Kind kind;
29+
std::string string;
30+
};
31+
32+
#endif

core/libjsonnet.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern "C" {
3030

3131
#include "desugarer.h"
3232
#include "formatter.h"
33+
#include "json.h"
3334
#include "parser.h"
3435
#include "static_analysis.h"
3536
#include "vm.h"
@@ -50,6 +51,25 @@ static char *from_string(JsonnetVm* vm, const std::string &v)
5051
static char *default_import_callback(void *ctx, const char *dir, const char *file,
5152
char **found_here_cptr, int *success);
5253

54+
const char *jsonnet_json_extract_string(JsonnetVm *vm, const struct JsonnetJsonValue *v)
55+
{
56+
(void) vm;
57+
if (v->kind != JsonnetJsonValue::STRING)
58+
return nullptr;
59+
return v->string.c_str();
60+
}
61+
62+
/** Convert the given UTF8 string to a JsonnetJsonValue.
63+
*/
64+
JsonnetJsonValue *jsonnet_json_make_string(JsonnetVm *vm, const char *v)
65+
{
66+
(void) vm;
67+
JsonnetJsonValue *r = new JsonnetJsonValue();
68+
r->kind = JsonnetJsonValue::STRING;
69+
r->string = v;
70+
return r;
71+
}
72+
5373
struct JsonnetVm {
5474
double gcGrowthTrigger;
5575
unsigned maxStack;
@@ -58,6 +78,7 @@ struct JsonnetVm {
5878
std::map<std::string, VmExt> ext;
5979
std::map<std::string, VmExt> tla;
6080
JsonnetImportCallback *importCallback;
81+
VmNativeCallbackMap nativeCallbacks;
6182
void *importCallbackContext;
6283
bool stringOutput;
6384
std::vector<std::string> jpaths;
@@ -212,6 +233,16 @@ void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, vo
212233
vm->importCallbackContext = ctx;
213234
}
214235

236+
void jsonnet_native_callback(struct JsonnetVm *vm, const char *name, JsonnetNativeCallback *cb,
237+
void *ctx, const char * const *params)
238+
{
239+
std::vector<std::string> params2;
240+
for (; *params != nullptr; params++)
241+
params2.push_back(*params);
242+
vm->nativeCallbacks[name] = VmNativeCallback {cb, ctx, params2};
243+
}
244+
245+
215246
void jsonnet_ext_var(JsonnetVm *vm, const char *key, const char *val)
216247
{
217248
vm->ext[key] = VmExt(val, false);
@@ -373,8 +404,8 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename,
373404
case REGULAR: {
374405
std::string json_str = jsonnet_vm_execute(
375406
&alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects,
376-
vm->gcGrowthTrigger, vm->importCallback, vm->importCallbackContext,
377-
vm->stringOutput);
407+
vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback,
408+
vm->importCallbackContext, vm->stringOutput);
378409
json_str += "\n";
379410
*error = false;
380411
return from_string(vm, json_str);
@@ -384,8 +415,8 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename,
384415
case MULTI: {
385416
std::map<std::string, std::string> files = jsonnet_vm_execute_multi(
386417
&alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects,
387-
vm->gcGrowthTrigger, vm->importCallback, vm->importCallbackContext,
388-
vm->stringOutput);
418+
vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback,
419+
vm->importCallbackContext, vm->stringOutput);
389420
size_t sz = 1; // final sentinel
390421
for (const auto &pair : files) {
391422
sz += pair.first.length() + 1; // include sentinel
@@ -413,7 +444,8 @@ static char *jsonnet_evaluate_snippet_aux(JsonnetVm *vm, const char *filename,
413444
case STREAM: {
414445
std::vector<std::string> documents = jsonnet_vm_execute_stream(
415446
&alloc, expr, vm->ext, vm->maxStack, vm->gcMinObjects,
416-
vm->gcGrowthTrigger, vm->importCallback, vm->importCallbackContext);
447+
vm->gcGrowthTrigger, vm->nativeCallbacks, vm->importCallback,
448+
vm->importCallbackContext);
417449
size_t sz = 1; // final sentinel
418450
for (const auto &doc : documents) {
419451
sz += doc.length() + 2; // Add a '\n' as well as sentinel

core/libjsonnet_test_snippet.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,40 @@ limitations under the License.
1616

1717
#include <stdlib.h>
1818
#include <stdio.h>
19+
#include <string.h>
1920

2021
#include <libjsonnet.h>
2122

23+
struct JsonnetJsonValue *concat(void *ctx, const struct JsonnetJsonValue * const *argv, int *succ)
24+
{
25+
struct JsonnetVm *vm = (struct JsonnetVm *)ctx;
26+
const char *a = jsonnet_json_extract_string(vm, argv[0]);
27+
const char *b = jsonnet_json_extract_string(vm, argv[1]);
28+
if (a == NULL || b == NULL) {
29+
struct JsonnetJsonValue *r = jsonnet_json_make_string(vm, "Bad params.");
30+
*succ = 0;
31+
return r;
32+
}
33+
char *str = malloc(strlen(a) + strlen(b) + 1);
34+
sprintf(str, "%s%s", a, b);
35+
struct JsonnetJsonValue *r = jsonnet_json_make_string(vm, str);
36+
free(str);
37+
*succ = 1;
38+
return r;
39+
}
40+
2241
int main(int argc, const char **argv)
2342
{
2443
int error;
2544
char *output;
2645
struct JsonnetVm *vm;
46+
const char *params[] = {"a", "b", NULL};
2747
if (argc != 2) {
2848
fprintf(stderr, "libjsonnet_test_snippet <string>\n");
2949
return EXIT_FAILURE;
3050
}
3151
vm = jsonnet_make();
52+
jsonnet_native_callback(vm, "concat", concat, vm, params);
3253
output = jsonnet_evaluate_snippet(vm, "snippet", argv[1], &error);
3354
if (error) {
3455
fprintf(stderr, "%s", output);

core/parser.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,6 @@ AST *jsonnet_parse(Allocator *alloc, Tokens &tokens);
3636
*/
3737
std::string jsonnet_unparse_number(double v);
3838

39-
struct BuiltinDecl {
40-
String name;
41-
std::vector<String> params;
42-
};
43-
44-
/** Returns the signature of each built-in function. */
45-
BuiltinDecl jsonnet_builtin_decl(unsigned long builtin);
46-
4739
/** The inverse of jsonnet_parse.
4840
*/
4941
std::string jsonnet_unparse_jsonnet(const AST *ast, const Fodder &final_fodder, unsigned indent,

core/state.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ struct HeapComprehensionObject : public HeapLeafObject {
221221

222222
/** Stores the function itself and also the captured environment.
223223
*
224-
* Either body is non-null and builtin is 0, or body is null and builtin refers to a built-in
224+
* Either body is non-null and builtinName is "", or body is null and builtin refers to a built-in
225225
* function. In the former case, the closure represents a user function, otherwise calling it
226226
* will trigger the builtin function to execute. Params is empty when the function is a
227227
* builtin.
@@ -243,14 +243,14 @@ struct HeapClosure : public HeapEntity {
243243
typedef std::vector<Param> Params;
244244
const Params params;
245245
const AST *body;
246-
const unsigned long builtin;
246+
std::string builtinName;
247247
HeapClosure(const BindingFrame &up_values,
248248
HeapObject *self,
249249
unsigned offset,
250250
const Params &params,
251-
const AST *body, unsigned long builtin)
251+
const AST *body, const std::string &builtin_name)
252252
: upValues(up_values), self(self), offset(offset),
253-
params(params), body(body), builtin(builtin)
253+
params(params), body(body), builtinName(builtin_name)
254254
{ }
255255
};
256256

0 commit comments

Comments
 (0)