├── .gitignore ├── LICENSE ├── Makefile ├── README.markdown ├── example ├── bar_menu.2.jsonnet ├── bar_menu.3.jsonnet ├── bar_menu.5.jsonnet ├── bar_menu.6.jsonnet ├── bar_menu_utils.jsonnet ├── evaluate_file.lua ├── evaluate_snippet.lua ├── example_operators.jsonnet ├── fibonacci.jsonnet ├── martinis.jsonnet └── t.jsonnet ├── jsonnet.lua └── libjsonnet ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README ├── _jsonnet.c ├── ast.h ├── jsonnet.cpp ├── jsonnet_test_file.py ├── jsonnet_test_snippet.py ├── lexer.cpp ├── lexer.h ├── libjsonnet.cpp ├── libjsonnet.h ├── libjsonnet_test_file.c ├── libjsonnet_test_snippet.c ├── parser.cpp ├── parser.h ├── setup.py ├── state.h ├── static_analysis.cpp ├── static_analysis.h ├── static_error.h ├── std.jsonnet ├── vm.cpp └── vm.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Lua sources 2 | luac.out 3 | 4 | # luarocks build files 5 | *.src.rock 6 | *.zip 7 | *.tar.gz 8 | 9 | # Object files 10 | *.o 11 | *.os 12 | *.ko 13 | *.obj 14 | *.elf 15 | 16 | # Precompiled Headers 17 | *.gch 18 | *.pch 19 | 20 | # Libraries 21 | *.lib 22 | *.a 23 | *.la 24 | *.lo 25 | *.def 26 | *.exp 27 | 28 | # Shared objects (inc. Windows DLLs) 29 | *.dll 30 | *.so 31 | *.so.* 32 | *.dylib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | *.i*86 39 | *.x86_64 40 | *.hex 41 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIB = /usr/lib64/ 2 | exist = $(shell if [ -f $(LIB) ]; then echo "true"; else echo "false"; fi;) 3 | ifeq (exist, "false") 4 | LIB = /usr/lib/ 5 | endif 6 | install: 7 | cd libjsonnet && make libjsonnet.so && cp libjsonnet.so $(LIB) && cd ../ && cp jsonnet.lua /usr/local/share/luajit-*/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Name 2 | ==== 3 | |luarocks| 4 | |:------:| 5 | |[![](https://img.shields.io/badge/luarocks-0.1--1-blue.svg)](https://luarocks.org/modules/chenyuduan/jsonnet)| 6 | 7 | luajit-jsonnet - The Google Jsonnet( operation data template language) for Luajit 8 | 9 | 10 | Table of Contents 11 | ================= 12 | 13 | * [Name](#name) 14 | * [Description](#description) 15 | * [install](#install) 16 | * [Methods](#methods) 17 | * [new](#new) 18 | * [make](#make) 19 | * [evaluate_file](#evaluate_file) 20 | * [evaluate_snippet](#evaluate_snippet) 21 | * [evaluate_file_multi](#evaluate_file_multi) 22 | * [evaluate_snippet_multi](#evaluate_snippet_multi) 23 | * [destroy](#destroy) 24 | 25 | Description 26 | =========== 27 | 28 | 29 | jsonnet is a domain specific configuration language that helps you define JSON data. Jsonnet lets you compute fragments of JSON within the structure, bringing the same benefit to structured data that templating languages bring to plain text. The example below illustrates a few features -- referring to another part of the structure, overriding object fields, and string operations...... 30 | 31 | luajit-jsonnet - Use the luajit ffi jsonnet interface calls and operation 32 | 33 | Google jsonnet documet: (http://google.github.io/jsonnet/doc/) 34 | 35 | install 36 | =========== 37 | Simple executing the following command 38 | 39 | ``` 40 | make install 41 | 42 | ``` 43 | 44 | Methods 45 | ======= 46 | 47 | new 48 | --- 49 | Create a luajit - jsonnet object 50 | 51 | ``` 52 | local jso = require "jsonnet" 53 | jsonnet = jso:new() 54 | 55 | ``` 56 | make 57 | --- 58 | Create a new Jsonnet virtual machine. 59 | 60 | ``` 61 | syntax: res, err = jsonnet:make() 62 | ``` 63 | evaluate_file 64 | --- 65 | Evaluate a file containing Jsonnet code, return a JSON string. 66 | 67 | ``` 68 | syntax: res,err = jsonnet:evaluate_file("t.jsonnet") 69 | ``` 70 | ``` 71 | local jso = require "jsonnet" 72 | jsonnet = jso:new() 73 | jsonnet:make() 74 | res,err = jsonnet:evaluate_file("t.jsonnet") 75 | if err == nil then 76 | print(res) 77 | else 78 | print(err) 79 | end 80 | ``` 81 | evaluate_snippet 82 | --- 83 | Evaluate a file containing Jsonnet code, return a JSON string. 84 | 85 | ``` 86 | syntax: res,err = jsonnet:evaluate_snippet(snippet) 87 | ``` 88 | 89 | ``` 90 | local snippet = '{ person1: { name: "Alice", welcome: "Hello " + self.name + "!", }, person2: self.person1 { name: "Bob" },}' 91 | res,err = jsonnet:evaluate_snippet(snippet) 92 | if err == nil then 93 | print(res) 94 | else 95 | print(err) 96 | end 97 | ``` 98 | 99 | evaluate_file_multi 100 | --- 101 | Evaluate a file containing Jsonnet code, return a number of JSON files. The returned character buffer contains an even number of strings, the filename and JSON for each 102 | 103 | ``` 104 | syntax: res,err = jsonnet:evaluate_file_multi("t.jsonnet") 105 | ``` 106 | 107 | 108 | evaluate_snippet_multi 109 | --- 110 | Evaluate a string containing Jsonnet code, return a number of JSON files. The returned character buffer contains an even number of strings, the filename and JSON for each 111 | 112 | ``` 113 | syntax: res,err = jsonnet:evaluate_snippet_multi(snippet) 114 | ``` 115 | 116 | 117 | destroy 118 | --- 119 | Shut down and release Jsonnet virtual machine. 120 | 121 | ``` 122 | syntax: res,err = jsonnet:destroy(vm) 123 | ``` 124 | 125 | ``` 126 | local jso = require "jsonnet" 127 | jsonnet = jso:new() 128 | jsonnet:make() 129 | res,err = jsonnet:evaluate_file("t.jsonnet") 130 | jsonnet:destroy() 131 | ``` 132 | 133 | Author 134 | ====== 135 | 136 | Yuduan Chen (陈毓端) 137 | -------------------------------------------------------------------------------- /example/bar_menu.2.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | cocktails: { 3 | "Tom Collins": { 4 | ingredients: [ 5 | { kind: "Farmers Gin", qty: 1.5 }, 6 | { kind: "Lemon", qty: 1 }, 7 | { kind: "Simple Syrup", qty: 0.5 }, 8 | { kind: "Soda", qty: 2 }, 9 | { kind: "Angostura", qty: "dash" }, 10 | ], 11 | garnish: "Maraschino Cherry", 12 | served: "Tall", 13 | }, 14 | Martini: { 15 | ingredients: [ 16 | { 17 | // Evaluate a path to get the first ingredient of the Tom Collins. 18 | kind: $.cocktails["Tom Collins"].ingredients[0].kind, 19 | // or $["cocktails"]["Tom Collins"]["ingredients"][0]["kind"], 20 | qty: 1 21 | }, 22 | { kind: "Dry White Vermouth", qty: 1 }, 23 | ], 24 | garnish: "Olive", 25 | served: "Straight Up", 26 | }, 27 | "Gin Martini": self.Martini, 28 | } 29 | } -------------------------------------------------------------------------------- /example/bar_menu.3.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | foo: 3, 3 | bar: 2 * self.foo, // Multiplication. 4 | baz: "The value " + self.bar + " is " 5 | + (if self.bar > 5 then "large" else "small") + ".", 6 | array: [1, 2, 3] + [4], 7 | obj: {a: 1, b: 2} + {b: 3, c: 4}, 8 | equality: 1 == "1", 9 | } -------------------------------------------------------------------------------- /example/bar_menu.5.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | cocktails: { 3 | "Bee's Knees": { 4 | // Construct the ingredients by using 4/3 oz 5 | // of each element in the given list. 6 | ingredients: [ // Array comprehension. 7 | { kind: i, qty: 4/3 } 8 | for i in ["Honey Syrup", "Lemon Juice", "Farmers Gin"] 9 | ], 10 | garnish: "Lemon Twist", 11 | served: "Straight Up", 12 | }, 13 | } + { // Object comprehension. 14 | [sd.name + "Screwdriver"]: { 15 | ingredients: [ 16 | { kind: "Vodka", qty: 1.5 }, 17 | { kind: sd.fruit, qty: 3 }, 18 | ], 19 | garnish: null, 20 | served: "On The Rocks" 21 | } for sd in [ 22 | {name: "Yellow ", fruit: "Lemonade"}, 23 | {name: "", fruit: "Orange Juice"}, 24 | ] 25 | } 26 | } -------------------------------------------------------------------------------- /example/bar_menu.6.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | cocktails: import "martinis.jsonnet" + { 3 | Manhattan: { 4 | ingredients: [ 5 | { kind: "Rye", qty: 2.5 }, 6 | { kind: "Sweet Red Vermouth", qty: 1 }, 7 | { kind: "Angostura", qty: "dash" }, 8 | ], 9 | garnish: "Maraschino Cherry", 10 | served: "Straight Up", 11 | }, 12 | Cosmopolitan: { 13 | ingredients: [ 14 | { kind: "Vodka", qty: 1.5 }, 15 | { kind: "Cointreau", qty: 1 }, 16 | { kind: "Cranberry Juice", qty: 2 }, 17 | { kind: "Lime Juice", qty: 1 }, 18 | ], 19 | garnish: "Lime Wheel", 20 | served: "Straight Up", 21 | }, 22 | } 23 | } -------------------------------------------------------------------------------- /example/bar_menu_utils.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | equal_parts(size, ingredients):: 3 | if std.length(ingredients) == 0 then 4 | error "No ingredients specified." 5 | else [ 6 | { kind: i, qty: size/std.length(ingredients) } 7 | for i in ingredients 8 | ], 9 | id:: function(x) x, 10 | } -------------------------------------------------------------------------------- /example/evaluate_file.lua: -------------------------------------------------------------------------------- 1 | local jso = require "jsonnet" 2 | jsonnet = jso:new() 3 | jsonnet:make() 4 | if arg[1] ~= nil then 5 | filename = arg[1] 6 | else 7 | filename = "t.jsonnet" 8 | end 9 | res,err = jsonnet:evaluate_file(filename) 10 | jsonnet:destroy() 11 | if err == nil then 12 | print(res) 13 | else 14 | print(err) 15 | end -------------------------------------------------------------------------------- /example/evaluate_snippet.lua: -------------------------------------------------------------------------------- 1 | local jso = require "jsonnet" 2 | jsonnet = jso:new() 3 | jsonnet:make() 4 | print("------- Normal test data --------") 5 | local snippet = '{ person1: { name: "Alice", welcome: "Hello " + self.name + "!", }, person2: self.person1 { name: "Bob" },}' 6 | res,err = jsonnet:evaluate_snippet(snippet) 7 | if err == nil then 8 | print(res) 9 | else 10 | print(err) 11 | end 12 | 13 | print("------- Abnormal test data --------") 14 | local snippet = '!@##$@%$%^%&{ person1: { name: "Alice", welcome: "Hello " + self.name + "!", }, person2: self.person1 { name: "Bob" },}' 15 | res,err = jsonnet:evaluate_snippet(snippet) 16 | if err == nil then 17 | print(res) 18 | else 19 | print(err) 20 | end 21 | jsonnet:destroy() -------------------------------------------------------------------------------- /example/example_operators.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | foo: [1, 2, 3], 3 | bar: [x * x for x in self.foo if x >= 2], 4 | baz: { ["field" + x]: x for x in self.foo }, 5 | obj: { ["foo" + "bar"]: 3 }, 6 | } -------------------------------------------------------------------------------- /example/fibonacci.jsonnet: -------------------------------------------------------------------------------- 1 | local fibonacci(n) = 2 | if n <= 1 then 3 | 1 4 | else 5 | fibonacci(n - 1) + fibonacci(n - 2); 6 | 7 | fibonacci(25) 8 | -------------------------------------------------------------------------------- /example/martinis.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | "Vodka Martini": { 3 | ingredients: [ 4 | { kind: "Vodka", qty: 2 }, 5 | { kind: "Dry White Vermouth", qty: 1 }, 6 | ], 7 | garnish: "Olive", 8 | served: "Straight Up", 9 | }, 10 | Cosmopolitan: { 11 | ingredients: [ 12 | { kind: "Vodka", qty: 2 }, 13 | { kind: "Triple Sec", qty: 0.5 }, 14 | { kind: "Cranberry Juice", qty: 0.75 }, 15 | { kind: "Lime Juice", qty: 0.5 }, 16 | ], 17 | garnish: "Orange Peel", 18 | served: "Straight Up", 19 | }, 20 | } -------------------------------------------------------------------------------- /example/t.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | person1: { 3 | name: "Alice", 4 | welcome: "Hello " + self.name + "!", 5 | }, 6 | person2: self.person1 { name: "Bob" }, 7 | } -------------------------------------------------------------------------------- /jsonnet.lua: -------------------------------------------------------------------------------- 1 | local ffi = require "ffi" 2 | local ffi_new = ffi.new 3 | local ffi_str = ffi.string 4 | local C = ffi.C 5 | local setmetatable = setmetatable 6 | local error = error 7 | local libjsonnet = ffi.load(ffi.os == "Windows" and "libjsonnet" or "libjsonnet") 8 | local _M = { _VERSION = '0.01' } 9 | local mt = { __index = _M } 10 | ffi.cdef[[ 11 | const char *jsonnet_version(void); 12 | typedef struct JsonnetVm {struct JsonnetVm *vm;char* out; const char *version;} JsonnetVm_t; 13 | struct JsonnetVm *jsonnet_make(void); 14 | void jsonnet_max_stack(struct JsonnetVm *vm, unsigned v); 15 | void jsonnet_gc_min_objects(struct JsonnetVm *vm, unsigned v); 16 | void jsonnet_gc_growth_trigger(struct JsonnetVm *vm, double v); 17 | void jsonnet_string_output(struct JsonnetVm *vm, int v); 18 | typedef char *JsonnetImportCallback(void *ctx, const char *base, const char *rel, int *success); 19 | char *jsonnet_realloc(struct JsonnetVm *vm, char *buf, size_t sz); 20 | void jsonnet_import_callback(struct JsonnetVm *vm, JsonnetImportCallback *cb, void *ctx); 21 | void jsonnet_ext_var(struct JsonnetVm *vm, const char *key, const char *val); 22 | void jsonnet_debug_ast(struct JsonnetVm *vm, int v); 23 | char *jsonnet_evaluate_file(struct JsonnetVm *vm,const char *filename,int *error); 24 | char *jsonnet_evaluate_snippet(struct JsonnetVm *vm,const char *filename,const char *snippet,int *error); 25 | char *jsonnet_evaluate_file_multi(struct JsonnetVm *vm, const char *filename,int *error); 26 | char *jsonnet_evaluate_snippet_multi(struct JsonnetVm *vm,const char *filename, const char *snippet,int *error); 27 | void jsonnet_destroy(struct JsonnetVm *vm); 28 | ]] 29 | local int_ptr = ffi.typeof("int[1]") 30 | local JsonnetVm = ffi.new("JsonnetVm_t") 31 | local _vm; 32 | local _err_jsonnet_make_init = "jsonnet_make not initialized" 33 | local function _return( err,res ,out ) 34 | libjsonnet.jsonnet_realloc(_vm, out,0) 35 | if tonumber(err[0]) == 1 then 36 | return nil,res 37 | else 38 | return res,nil 39 | end 40 | end 41 | 42 | function _M.new(self) 43 | return setmetatable({ }, mt) 44 | end 45 | 46 | function _M.make(self) 47 | _vm = libjsonnet.jsonnet_make() 48 | end 49 | 50 | function _M.version(self) 51 | JsonnetVm.version = libjsonnet.jsonnet_version(); 52 | return ffi.string(JsonnetVm.version) 53 | end 54 | 55 | function _M.evaluate_file( self , filename ) 56 | local err = int_ptr() 57 | if _vm == nil then 58 | return nil ,_err_jsonnet_make_init 59 | end 60 | JsonnetVm.out = libjsonnet.jsonnet_evaluate_file(_vm,filename,err) 61 | local res = ffi.string(JsonnetVm.out) 62 | err,res = _return(err,res,JsonnetVm.out) 63 | return err,res 64 | end 65 | 66 | function _M.evaluate_snippet( self ,snippet ) 67 | local err = int_ptr() 68 | if _vm == nil then 69 | return nil ,_err_jsonnet_make_init 70 | end 71 | JsonnetVm.out = libjsonnet.jsonnet_evaluate_snippet(_vm,"snippet",snippet,err) 72 | local res = ffi.string(JsonnetVm.out) 73 | err,res = _return(err,res,JsonnetVm.out) 74 | return err,res 75 | end 76 | 77 | function _M.evaluate_file_multi( self , filename ) 78 | local err = int_ptr() 79 | if _vm == nil then 80 | return nil ,_err_jsonnet_make_init 81 | end 82 | JsonnetVm.out = libjsonnet.jsonnet_evaluate_file_multi(_vm,filename,err) 83 | local res = ffi.string(JsonnetVm.out) 84 | err,res = _return(err,res,JsonnetVm.out) 85 | return err,res 86 | end 87 | 88 | function _M.evaluate_snippet_multi( self ,snippet ) 89 | local err = int_ptr() 90 | if _vm == nil then 91 | return nil ,_err_jsonnet_make_init 92 | end 93 | JsonnetVm.out = libjsonnet.jsonnet_evaluate_snippet_multi(_vm,"snippet",snippet,err) 94 | local res = ffi.string(JsonnetVm.out) 95 | err,res = _return(err,res,JsonnetVm.out) 96 | return err,res 97 | end 98 | 99 | function _M.destroy( self ) 100 | if _vm == nil then 101 | return nil ,_err_jsonnet_make_init 102 | end 103 | libjsonnet.jsonnet_destroy(_vm) 104 | _vm = nil 105 | end 106 | 107 | return _M -------------------------------------------------------------------------------- /libjsonnet/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /libjsonnet/MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE libjsonnet.h libjsonnet.cpp _jsonnet.c lexer.h lexer.cpp ast.h parser.h parser.cpp static_error.h static_analysis.h static_analysis.cpp state.h vm.h vm.cpp std.jsonnet Makefile 2 | #recursive-include test_suite examples gc_stress benchmarks editors 3 | -------------------------------------------------------------------------------- /libjsonnet/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright 2015 Google Inc. All rights reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | ################################################################################################### 16 | # User-servicable parts: 17 | ################################################################################################### 18 | 19 | # C/C++ compiler -- clang also works 20 | CXX ?= g++ 21 | CC ?= gcc 22 | 23 | # Emscripten -- For Jsonnet in the browser 24 | EMCXX ?= em++ 25 | EMCC ?= emcc 26 | 27 | CP ?= cp 28 | OD ?= od 29 | 30 | CXXFLAGS ?= -g -O3 -Wall -Wextra -pedantic -std=c++0x -fPIC 31 | CFLAGS ?= -g -O3 -Wall -Wextra -pedantic -std=c99 -fPIC 32 | EMCXXFLAGS = $(CXXFLAGS) --memory-init-file 0 -s DISABLE_EXCEPTION_CATCHING=0 33 | EMCFLAGS = $(CFLAGS) --memory-init-file 0 -s DISABLE_EXCEPTION_CATCHING=0 34 | LDFLAGS ?= 35 | 36 | SHARED_LDFLAGS ?= -shared 37 | 38 | ################################################################################################### 39 | # End of user-servicable parts 40 | ################################################################################################### 41 | 42 | LIB_SRC = lexer.cpp parser.cpp static_analysis.cpp vm.cpp libjsonnet.cpp 43 | LIB_OBJ = $(LIB_SRC:.cpp=.o) 44 | 45 | ALL = jsonnet libjsonnet.so libjsonnet_test_snippet libjsonnet_test_file libjsonnet.js doc/libjsonnet.js $(LIB_OBJ) 46 | ALL_HEADERS = libjsonnet.h vm.h static_analysis.h parser.h lexer.h ast.h static_error.h state.h std.jsonnet.h 47 | 48 | default: jsonnet 49 | 50 | all: $(ALL) 51 | 52 | TEST_SNIPPET = "std.assertEqual(({ x: 1, y: self.x } { x: 2 }).y, 2)" 53 | test: jsonnet libjsonnet.so libjsonnet_test_snippet libjsonnet_test_file 54 | ./jsonnet -e $(TEST_SNIPPET) 55 | LD_LIBRARY_PATH=. ./libjsonnet_test_snippet $(TEST_SNIPPET) 56 | LD_LIBRARY_PATH=. ./libjsonnet_test_file "test_suite/object.jsonnet" 57 | cd examples ; ./check.sh 58 | cd examples/terraform ; ./check.sh 59 | cd test_suite ; ./run_tests.sh 60 | 61 | depend: 62 | makedepend -f- $(LIB_SRC) jsonnet.cpp libjsonnet_test_snippet.c libjsonnet_test_file.c > Makefile.depend 63 | 64 | parser.cpp: std.jsonnet.h 65 | 66 | # Object files 67 | %.o: %.cpp 68 | $(CXX) -c $(CXXFLAGS) $< -o $@ 69 | 70 | # Commandline executable. 71 | jsonnet: jsonnet.cpp $(LIB_OBJ) 72 | $(CXX) $(CXXFLAGS) $(LDFLAGS) $< $(LIB_SRC:.cpp=.o) -o $@ 73 | 74 | # C binding. 75 | libjsonnet.so: $(LIB_OBJ) 76 | $(CXX) $(LDFLAGS) $(LIB_OBJ) $(SHARED_LDFLAGS) -o $@ 77 | 78 | # Javascript build of C binding 79 | libjsonnet.js: $(LIB_SRC) $(ALL_HEADERS) 80 | $(EMCXX) -s 'EXPORTED_FUNCTIONS=["_jsonnet_make", "_jsonnet_evaluate_snippet", "_jsonnet_realloc", "_jsonnet_destroy"]' $(EMCXXFLAGS) $(LDFLAGS) $(LIB_SRC) -o $@ 81 | 82 | # Copy javascript build to doc directory 83 | doc/libjsonnet.js: libjsonnet.js 84 | $(CP) $^ $@ 85 | 86 | # Tests for C binding. 87 | libjsonnet_test_snippet: libjsonnet_test_snippet.c libjsonnet.so libjsonnet.h 88 | $(CC) $(CFLAGS) $(LDFLAGS) $< -L. -ljsonnet -o $@ 89 | 90 | libjsonnet_test_file: libjsonnet_test_file.c libjsonnet.so libjsonnet.h 91 | $(CC) $(CFLAGS) $(LDFLAGS) $< -L. -ljsonnet -o $@ 92 | 93 | # Encode standard library for embedding in C 94 | %.jsonnet.h: %.jsonnet 95 | (($(OD) -v -Anone -t u1 $< | tr " " "\n" | grep -v "^$$" | tr "\n" "," ) && echo "0") > $@ 96 | echo >> $@ 97 | 98 | clean: 99 | rm -vf */*~ *~ .*~ */.*.swp .*.swp $(ALL) *.o *.jsonnet.h 100 | 101 | -include Makefile.depend 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /libjsonnet/README: -------------------------------------------------------------------------------- 1 | Jsonnet - The data templating language 2 | 3 | Website: http://google.github.io/jsonnet/doc/ 4 | Discussion Forum: https://groups.google.com/forum/#!forum/jsonnet 5 | -------------------------------------------------------------------------------- /libjsonnet/_jsonnet.c: -------------------------------------------------------------------------------- 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 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "libjsonnet.h" 23 | 24 | static PyObject* evaluate_file(PyObject* self, PyObject* args, PyObject *keywds) 25 | { 26 | const char *filename; 27 | char *out; 28 | unsigned max_stack = 500, gc_min_objects = 1000, max_trace = 20; 29 | double gc_growth_trigger = 2; 30 | int debug_ast = 0, error; 31 | PyObject *ext_vars = NULL; 32 | struct JsonnetVm *vm; 33 | static char *kwlist[] = {"filename", "max_stack", "gc_min_objects", "gc_growth_trigger", "ext_vars", "debug_ast", "max_trace", NULL}; 34 | 35 | (void) self; 36 | 37 | if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|IIdOiI", kwlist, 38 | &filename, 39 | &max_stack, &gc_min_objects, &gc_growth_trigger, &ext_vars, &debug_ast, &max_trace)) { 40 | return NULL; 41 | } 42 | 43 | vm = jsonnet_make(); 44 | jsonnet_max_stack(vm, max_stack); 45 | jsonnet_gc_min_objects(vm, gc_min_objects); 46 | jsonnet_max_trace(vm, max_trace); 47 | jsonnet_gc_growth_trigger(vm, gc_growth_trigger); 48 | jsonnet_debug_ast(vm, debug_ast); 49 | if (ext_vars != NULL) { 50 | PyObject *key, *val; 51 | Py_ssize_t pos = 0; 52 | 53 | while (PyDict_Next(ext_vars, &pos, &key, &val)) { 54 | const char *key_ = PyString_AsString(key); 55 | if (key_ == NULL) { 56 | jsonnet_destroy(vm); 57 | return NULL; 58 | } 59 | const char *val_ = PyString_AsString(val); 60 | if (val_ == NULL) { 61 | jsonnet_destroy(vm); 62 | return NULL; 63 | } 64 | jsonnet_ext_var(vm, key_, val_); 65 | } 66 | } 67 | 68 | out = jsonnet_evaluate_file(vm, filename, &error); 69 | if (error) { 70 | PyErr_SetString(PyExc_RuntimeError, out); 71 | jsonnet_realloc(vm, out, 0); 72 | jsonnet_destroy(vm); 73 | return NULL; 74 | } else { 75 | PyObject *ret = PyString_FromString(out); 76 | jsonnet_realloc(vm, out, 0); 77 | jsonnet_destroy(vm); 78 | return ret; 79 | } 80 | } 81 | 82 | static PyObject* evaluate_snippet(PyObject* self, PyObject* args, PyObject *keywds) 83 | { 84 | const char *filename, *src; 85 | char *out; 86 | unsigned max_stack = 500, gc_min_objects = 1000, max_trace = 20; 87 | double gc_growth_trigger = 2; 88 | int debug_ast = 0, error; 89 | PyObject *ext_vars = NULL; 90 | struct JsonnetVm *vm; 91 | static char *kwlist[] = {"filename", "src", "max_stack", "gc_min_objects", "gc_growth_trigger", "ext_vars", "debug_ast", "max_trace", NULL}; 92 | 93 | (void) self; 94 | 95 | if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|IIdOiI", kwlist, 96 | &filename, &src, 97 | &max_stack, &gc_min_objects, &gc_growth_trigger, &ext_vars, &debug_ast, &max_trace)) { 98 | return NULL; 99 | } 100 | 101 | vm = jsonnet_make(); 102 | jsonnet_max_stack(vm, max_stack); 103 | jsonnet_gc_min_objects(vm, gc_min_objects); 104 | jsonnet_max_trace(vm, max_trace); 105 | jsonnet_gc_growth_trigger(vm, gc_growth_trigger); 106 | jsonnet_debug_ast(vm, debug_ast); 107 | if (ext_vars != NULL) { 108 | PyObject *key, *val; 109 | Py_ssize_t pos = 0; 110 | 111 | while (PyDict_Next(ext_vars, &pos, &key, &val)) { 112 | const char *key_ = PyString_AsString(key); 113 | if (key_ == NULL) { 114 | jsonnet_destroy(vm); 115 | return NULL; 116 | } 117 | const char *val_ = PyString_AsString(val); 118 | if (val_ == NULL) { 119 | jsonnet_destroy(vm); 120 | return NULL; 121 | } 122 | jsonnet_ext_var(vm, key_, val_); 123 | } 124 | } 125 | 126 | out = jsonnet_evaluate_snippet(vm, filename, src, &error); 127 | if (error) { 128 | PyErr_SetString(PyExc_RuntimeError, out); 129 | jsonnet_realloc(vm, out, 0); 130 | jsonnet_destroy(vm); 131 | return NULL; 132 | } else { 133 | PyObject *ret = PyString_FromString(out); 134 | jsonnet_realloc(vm, out, 0); 135 | jsonnet_destroy(vm); 136 | return ret; 137 | } 138 | } 139 | 140 | static PyMethodDef module_methods[] = { 141 | {"evaluate_file", (PyCFunction)evaluate_file, METH_VARARGS | METH_KEYWORDS, 142 | "Interpret the given Jsonnet file."}, 143 | {"evaluate_snippet", (PyCFunction)evaluate_snippet, METH_VARARGS | METH_KEYWORDS, 144 | "Interpret the given Jsonnet code."}, 145 | {NULL, NULL, 0, NULL} 146 | }; 147 | 148 | PyMODINIT_FUNC init_jsonnet(void) 149 | { 150 | Py_InitModule3("_jsonnet", module_methods, "A Python interface to Jsonnet."); 151 | } 152 | 153 | -------------------------------------------------------------------------------- /libjsonnet/ast.h: -------------------------------------------------------------------------------- 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_AST_H 18 | #define JSONNET_AST_H 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "lexer.h" 28 | 29 | enum ASTType { 30 | AST_APPLY, 31 | AST_ARRAY, 32 | AST_BINARY, 33 | AST_BUILTIN_FUNCTION, 34 | AST_CONDITIONAL, 35 | AST_ERROR, 36 | AST_FUNCTION, 37 | AST_IMPORT, 38 | AST_IMPORTSTR, 39 | AST_INDEX, 40 | AST_LOCAL, 41 | AST_LITERAL_BOOLEAN, 42 | AST_LITERAL_NULL, 43 | AST_LITERAL_NUMBER, 44 | AST_LITERAL_STRING, 45 | AST_OBJECT, 46 | AST_OBJECT_COMPOSITION, 47 | AST_SELF, 48 | AST_SUPER, 49 | AST_UNARY, 50 | AST_VAR 51 | }; 52 | 53 | 54 | /** Represents a variable / parameter / field name. */ 55 | struct Identifier { 56 | std::string name; 57 | Identifier(const std::string &name) 58 | : name(name) 59 | { } 60 | }; 61 | 62 | static inline std::ostream &operator<<(std::ostream &o, const Identifier *id) 63 | { 64 | o << id->name; 65 | return o; 66 | } 67 | 68 | 69 | /** All AST nodes are subtypes of this class. 70 | */ 71 | struct AST { 72 | LocationRange location; 73 | ASTType type; 74 | std::vector freeVariables; 75 | AST(const LocationRange &location, ASTType type) 76 | : location(location), type(type) 77 | { 78 | } 79 | virtual ~AST(void) 80 | { 81 | } 82 | }; 83 | 84 | 85 | /** Represents function calls. */ 86 | struct Apply : public AST { 87 | AST *target; 88 | std::vector arguments; 89 | bool tailstrict; 90 | Apply(const LocationRange &lr, AST *target, const std::vector &arguments, bool tailstrict) 91 | : AST(lr, AST_APPLY), target(target), arguments(arguments), tailstrict(tailstrict) 92 | { } 93 | }; 94 | 95 | /** Represents array constructors [1, 2, 3]. */ 96 | struct Array : public AST { 97 | std::vector elements; 98 | Array(const LocationRange &lr, const std::vector &elements) 99 | : AST(lr, AST_ARRAY), elements(elements) 100 | { } 101 | }; 102 | 103 | enum BinaryOp { 104 | BOP_MULT, 105 | BOP_DIV, 106 | 107 | BOP_PLUS, 108 | BOP_MINUS, 109 | 110 | BOP_SHIFT_L, 111 | BOP_SHIFT_R, 112 | 113 | BOP_GREATER, 114 | BOP_GREATER_EQ, 115 | BOP_LESS, 116 | BOP_LESS_EQ, 117 | 118 | BOP_MANIFEST_EQUAL, 119 | BOP_MANIFEST_UNEQUAL, 120 | 121 | BOP_BITWISE_AND, 122 | BOP_BITWISE_XOR, 123 | BOP_BITWISE_OR, 124 | 125 | BOP_AND, 126 | BOP_OR 127 | }; 128 | 129 | static inline std::string bop_string (BinaryOp bop) 130 | { 131 | switch (bop) { 132 | case BOP_MULT: return "*"; 133 | case BOP_DIV: return "/"; 134 | 135 | case BOP_PLUS: return "+"; 136 | case BOP_MINUS: return "-"; 137 | 138 | case BOP_SHIFT_L: return "<<"; 139 | case BOP_SHIFT_R: return ">>"; 140 | 141 | case BOP_GREATER: return ">"; 142 | case BOP_GREATER_EQ: return ">="; 143 | case BOP_LESS: return "<"; 144 | case BOP_LESS_EQ: return "<="; 145 | 146 | case BOP_MANIFEST_EQUAL: return "=="; 147 | case BOP_MANIFEST_UNEQUAL: return "!="; 148 | 149 | case BOP_BITWISE_AND: return "&"; 150 | case BOP_BITWISE_XOR: return "^"; 151 | case BOP_BITWISE_OR: return "|"; 152 | 153 | case BOP_AND: return "&&"; 154 | case BOP_OR: return "||"; 155 | 156 | default: 157 | std::cerr << "INTERNAL ERROR: Unrecognised binary operator: " << bop << std::endl; 158 | std::abort(); 159 | } 160 | } 161 | 162 | /** Represents binary operators. */ 163 | struct Binary : public AST { 164 | AST *left; 165 | BinaryOp op; 166 | AST *right; 167 | Binary(const LocationRange &lr, AST *left, BinaryOp op, AST *right) 168 | : AST(lr, AST_BINARY), left(left), op(op), right(right) 169 | { } 170 | }; 171 | 172 | /** Represents built-in functions. 173 | * 174 | * There is no parse rule to build this AST. Instead, it is used to build the std object in the 175 | * interpreter. 176 | */ 177 | struct BuiltinFunction : public AST { 178 | unsigned long id; 179 | std::vector params; 180 | BuiltinFunction(const LocationRange &lr, unsigned long id, 181 | const std::vector ¶ms) 182 | : AST(lr, AST_BUILTIN_FUNCTION), id(id), params(params) 183 | { } 184 | }; 185 | 186 | /** Represents if then else. */ 187 | struct Conditional : public AST { 188 | AST *cond; 189 | AST *branchTrue; 190 | AST *branchFalse; 191 | Conditional(const LocationRange &lr, AST *cond, AST *branchTrue, AST *branchFalse) 192 | : AST(lr, AST_CONDITIONAL), cond(cond), branchTrue(branchTrue), branchFalse(branchFalse) 193 | { } 194 | }; 195 | 196 | /** Represents error e. */ 197 | struct Error : public AST { 198 | AST *expr; 199 | Error(const LocationRange &lr, AST *expr) 200 | : AST(lr, AST_ERROR), expr(expr) 201 | { } 202 | }; 203 | 204 | /** Represents function calls. */ 205 | struct Function : public AST { 206 | std::vector parameters; 207 | AST *body; 208 | Function(const LocationRange &lr, const std::vector ¶meters, AST *body) 209 | : AST(lr, AST_FUNCTION), parameters(parameters), body(body) 210 | { } 211 | }; 212 | 213 | /** Represents import "file". */ 214 | struct Import : public AST { 215 | std::string file; 216 | Import(const LocationRange &lr, const std::string &file) 217 | : AST(lr, AST_IMPORT), file(file) 218 | { } 219 | }; 220 | 221 | /** Represents importstr "file". */ 222 | struct Importstr : public AST { 223 | std::string file; 224 | Importstr(const LocationRange &lr, const std::string &file) 225 | : AST(lr, AST_IMPORTSTR), file(file) 226 | { } 227 | }; 228 | 229 | /** Represents both e[e] and the syntax sugar e.f. */ 230 | struct Index : public AST { 231 | AST *target; 232 | AST *index; 233 | Index(const LocationRange &lr, AST *target, AST *index) 234 | : AST(lr, AST_INDEX), target(target), index(index) 235 | { } 236 | }; 237 | 238 | /** Represents local x = e; e. */ 239 | struct Local : public AST { 240 | typedef std::map Binds; 241 | Binds binds; 242 | AST *body; 243 | Local(const LocationRange &lr, const Binds &binds, AST *body) 244 | : AST(lr, AST_LOCAL), binds(binds), body(body) 245 | { } 246 | }; 247 | 248 | /** Represents true and false. */ 249 | struct LiteralBoolean : public AST { 250 | bool value; 251 | LiteralBoolean(const LocationRange &lr, bool value) 252 | : AST(lr, AST_LITERAL_BOOLEAN), value(value) 253 | { } 254 | }; 255 | 256 | /** Represents the null keyword. */ 257 | struct LiteralNull : public AST { 258 | LiteralNull(const LocationRange &lr) 259 | : AST(lr, AST_LITERAL_NULL) 260 | { } 261 | }; 262 | 263 | /** Represents JSON numbers. */ 264 | struct LiteralNumber : public AST { 265 | double value; 266 | LiteralNumber(const LocationRange &lr, double value) 267 | : AST(lr, AST_LITERAL_NUMBER), value(value) 268 | { } 269 | }; 270 | 271 | /** Represents JSON strings. */ 272 | struct LiteralString : public AST { 273 | std::string value; 274 | LiteralString(const LocationRange &lr, const std::string &value) 275 | : AST(lr, AST_LITERAL_STRING), value(value) 276 | { } 277 | }; 278 | 279 | /** Represents object constructors { f: e ... }. */ 280 | struct Object : public AST { 281 | struct Field { 282 | enum Hide { 283 | INHERIT, // f: v 284 | HIDDEN, // f:: v 285 | VISIBLE // f::: v 286 | }; 287 | AST *name; 288 | enum Hide hide; 289 | AST *body; 290 | Field(AST *name, enum Hide hide, AST *body) 291 | : name(name), hide(hide), body(body) 292 | { } 293 | }; 294 | typedef std::list Fields; 295 | Fields fields; 296 | Object(const LocationRange &lr, const Fields &fields) 297 | : AST(lr, AST_OBJECT), fields(fields) 298 | { } 299 | }; 300 | 301 | /** Represents object composition { [e]: e for x in e }. */ 302 | struct ObjectComposition : public AST { 303 | AST *field; 304 | AST *value; 305 | const Identifier *id; 306 | AST *array; 307 | ObjectComposition(const LocationRange &lr, AST *field, AST *value, 308 | const Identifier *id, AST *array) 309 | : AST(lr, AST_OBJECT_COMPOSITION), field(field), value(value), id(id), array(array) 310 | { } 311 | }; 312 | 313 | /** Represents the self keyword. */ 314 | struct Self : public AST { 315 | Self(const LocationRange &lr) 316 | : AST(lr, AST_SELF) 317 | { } 318 | }; 319 | 320 | /** Represents the super keyword. */ 321 | struct Super : public AST { 322 | Super(const LocationRange &lr) 323 | : AST(lr, AST_SUPER) 324 | { } 325 | }; 326 | 327 | enum UnaryOp { 328 | UOP_NOT, 329 | UOP_BITWISE_NOT, 330 | UOP_PLUS, 331 | UOP_MINUS 332 | }; 333 | 334 | static inline std::string uop_string (UnaryOp uop) 335 | { 336 | switch (uop) { 337 | case UOP_PLUS: return "+"; 338 | case UOP_MINUS: return "-"; 339 | case UOP_BITWISE_NOT: return "~"; 340 | case UOP_NOT: return "!"; 341 | 342 | default: 343 | std::cerr << "INTERNAL ERROR: Unrecognised unary operator: " << uop << std::endl; 344 | std::abort(); 345 | } 346 | } 347 | 348 | /** Represents unary operators. */ 349 | struct Unary : public AST { 350 | UnaryOp op; 351 | AST *expr; 352 | Unary(const LocationRange &lr, UnaryOp op, AST *expr) 353 | : AST(lr, AST_UNARY), op(op), expr(expr) 354 | { } 355 | }; 356 | 357 | /** Represents variables. */ 358 | struct Var : public AST { 359 | const Identifier *id; 360 | const Identifier *original; 361 | Var(const LocationRange &lr, const Identifier *id) 362 | : AST(lr, AST_VAR), id(id), original(id) 363 | { } 364 | Var(const LocationRange &lr, const Identifier *id, const Identifier *original) 365 | : AST(lr, AST_VAR), id(id), original(original) 366 | { } 367 | }; 368 | 369 | 370 | /** Allocates ASTs on demand, frees them in its destructor. 371 | */ 372 | class Allocator { 373 | std::map internedIdentifiers; 374 | std::vector allocated; 375 | public: 376 | template T* make(Args... args) 377 | { 378 | auto r = new T(args...); 379 | allocated.push_back(r); 380 | return r; 381 | } 382 | /** Returns interned identifiers. 383 | * 384 | * The location used in the Identifier AST is that of the first one parsed. 385 | */ 386 | const Identifier *makeIdentifier(const std::string &name) 387 | { 388 | auto it = internedIdentifiers.find(name); 389 | if (it != internedIdentifiers.end()) { 390 | return it->second; 391 | } 392 | auto r = new Identifier(name); 393 | internedIdentifiers[name] = r; 394 | return r; 395 | } 396 | ~Allocator() 397 | { 398 | for (auto x : allocated) { 399 | delete x; 400 | } 401 | allocated.clear(); 402 | for (auto x : internedIdentifiers) { 403 | delete x.second; 404 | } 405 | internedIdentifiers.clear(); 406 | } 407 | }; 408 | 409 | #endif 410 | -------------------------------------------------------------------------------- /libjsonnet/jsonnet.cpp: -------------------------------------------------------------------------------- 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 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | extern "C" { 29 | #include "libjsonnet.h" 30 | } 31 | 32 | struct ImportCallbackContext { 33 | JsonnetVm *vm; 34 | std::vector *jpaths; 35 | }; 36 | 37 | enum ImportStatus { 38 | IMPORT_STATUS_OK, 39 | IMPORT_STATUS_FILE_NOT_FOUND, 40 | IMPORT_STATUS_IO_ERROR 41 | }; 42 | 43 | static enum ImportStatus try_path(const std::string &dir, const std::string &rel, 44 | std::string &content, std::string &err_msg) 45 | { 46 | std::string abs_path; 47 | if (rel.length() == 0) { 48 | err_msg = "The empty string is not a valid filename"; 49 | return IMPORT_STATUS_IO_ERROR; 50 | } 51 | // It is possible that rel is actually absolute. 52 | if (rel[0] == '/') { 53 | abs_path = rel; 54 | } else { 55 | abs_path = dir + rel; 56 | } 57 | 58 | if (abs_path[abs_path.length() - 1] == '/') { 59 | err_msg = "Attempted to import a directory"; 60 | return IMPORT_STATUS_IO_ERROR; 61 | } 62 | 63 | std::ifstream f; 64 | f.open(abs_path.c_str()); 65 | if (!f.good()) return IMPORT_STATUS_FILE_NOT_FOUND; 66 | try { 67 | content.assign(std::istreambuf_iterator(f), std::istreambuf_iterator()); 68 | } catch (const std::ios_base::failure &io_err) { 69 | err_msg = io_err.what(); 70 | return IMPORT_STATUS_IO_ERROR; 71 | } 72 | if (!f.good()) { 73 | err_msg = strerror(errno); 74 | return IMPORT_STATUS_IO_ERROR; 75 | } 76 | 77 | return IMPORT_STATUS_OK; 78 | } 79 | 80 | static char *import_callback (void *ctx_, const char *dir, const char *file, int *success) 81 | { 82 | const auto &ctx = *static_cast(ctx_); 83 | 84 | std::string input; 85 | 86 | std::string err_msg; 87 | 88 | ImportStatus status = try_path(dir, file, input, err_msg); 89 | 90 | std::vector jpaths(*ctx.jpaths); 91 | 92 | // If not found, try library search path. 93 | while (status == IMPORT_STATUS_FILE_NOT_FOUND) { 94 | if (jpaths.size() == 0) { 95 | *success = 0; 96 | const char *err = "No match locally or in the Jsonnet library path."; 97 | char *r = jsonnet_realloc(ctx.vm, nullptr, std::strlen(err) + 1); 98 | std::strcpy(r, err); 99 | return r; 100 | } 101 | status = try_path(jpaths.back(), file, input, err_msg); 102 | jpaths.pop_back(); 103 | } 104 | 105 | if (status == IMPORT_STATUS_IO_ERROR) { 106 | *success = 0; 107 | char *r = jsonnet_realloc(ctx.vm, nullptr, err_msg.length() + 1); 108 | std::strcpy(r, err_msg.c_str()); 109 | return r; 110 | } else { 111 | assert(status == IMPORT_STATUS_OK); 112 | *success = 1; 113 | char *r = jsonnet_realloc(ctx.vm, nullptr, input.length() + 1); 114 | std::strcpy(r, input.c_str()); 115 | return r; 116 | } 117 | } 118 | 119 | std::string next_arg(unsigned &i, const std::vector &args) 120 | { 121 | i++; 122 | if (i >= args.size()) { 123 | std::cerr << "Expected another commandline argument." << std::endl; 124 | exit(EXIT_FAILURE); 125 | } 126 | return args[i]; 127 | } 128 | 129 | /** Collect commandline args into a vector of strings, and expand -foo to -f -o -o. */ 130 | std::vector simplify_args(int argc, const char **argv) 131 | { 132 | std::vector r; 133 | for (int i=1 ; i 2 && arg[0] == '-' && arg[1] != '-') { 144 | for (unsigned j=1 ; j} \n"; 164 | o << "where can be - (stdin)\n"; 165 | o << "and