@port-labs/jq-node-bindings 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/.editorconfig +5 -0
  2. package/.jshintignore +1 -0
  3. package/.jshintrc +23 -0
  4. package/binding.gyp +56 -0
  5. package/configure +26 -0
  6. package/deps/jq/.gitattributes +2 -0
  7. package/deps/jq/.travis.yml +53 -0
  8. package/deps/jq/AUTHORS +73 -0
  9. package/deps/jq/COPYING +70 -0
  10. package/deps/jq/ChangeLog +1349 -0
  11. package/deps/jq/Makefile.am +198 -0
  12. package/deps/jq/NEWS +88 -0
  13. package/deps/jq/README.md +64 -0
  14. package/deps/jq/builtin.c +1684 -0
  15. package/deps/jq/builtin.h +10 -0
  16. package/deps/jq/bytecode.c +161 -0
  17. package/deps/jq/bytecode.h +92 -0
  18. package/deps/jq/compile-ios.sh +102 -0
  19. package/deps/jq/compile.c +1210 -0
  20. package/deps/jq/compile.h +101 -0
  21. package/deps/jq/config/m4/check-math-func.m4 +4 -0
  22. package/deps/jq/config/m4/find-func-no-libs.m4 +8 -0
  23. package/deps/jq/config/m4/find-func-no-libs2.m4 +62 -0
  24. package/deps/jq/config/m4/find-func.m4 +9 -0
  25. package/deps/jq/config/m4/misc.m4 +3 -0
  26. package/deps/jq/configure.ac +221 -0
  27. package/deps/jq/docs/Gemfile +7 -0
  28. package/deps/jq/docs/Gemfile.lock +63 -0
  29. package/deps/jq/docs/README.md +25 -0
  30. package/deps/jq/docs/Rakefile +145 -0
  31. package/deps/jq/docs/content/1.tutorial/default.yml +327 -0
  32. package/deps/jq/docs/content/2.download/default.yml +117 -0
  33. package/deps/jq/docs/content/3.manual/manual.yml +2878 -0
  34. package/deps/jq/docs/content/3.manual/v1.3/manual.yml +1270 -0
  35. package/deps/jq/docs/content/3.manual/v1.4/manual.yml +1672 -0
  36. package/deps/jq/docs/content/index/index.yml +51 -0
  37. package/deps/jq/docs/default_manpage.md +22 -0
  38. package/deps/jq/docs/public/.htaccess +28 -0
  39. package/deps/jq/docs/public/bootstrap/css/bootstrap-responsive.css +1058 -0
  40. package/deps/jq/docs/public/bootstrap/css/bootstrap-responsive.min.css +9 -0
  41. package/deps/jq/docs/public/bootstrap/css/bootstrap.css +5224 -0
  42. package/deps/jq/docs/public/bootstrap/css/bootstrap.min.css +9 -0
  43. package/deps/jq/docs/public/bootstrap/img/glyphicons-halflings-white.png +0 -0
  44. package/deps/jq/docs/public/bootstrap/img/glyphicons-halflings.png +0 -0
  45. package/deps/jq/docs/public/bootstrap/js/bootstrap.js +2027 -0
  46. package/deps/jq/docs/public/bootstrap/js/bootstrap.min.js +6 -0
  47. package/deps/jq/docs/public/css/base.scss +99 -0
  48. package/deps/jq/docs/public/jq.png +0 -0
  49. package/deps/jq/docs/public/robots.txt +2 -0
  50. package/deps/jq/docs/site.yml +18 -0
  51. package/deps/jq/docs/templates/default.liquid +34 -0
  52. package/deps/jq/docs/templates/index.liquid +60 -0
  53. package/deps/jq/docs/templates/manual.liquid +122 -0
  54. package/deps/jq/docs/templates/shared/_footer.liquid +5 -0
  55. package/deps/jq/docs/templates/shared/_head.liquid +12 -0
  56. package/deps/jq/docs/templates/shared/_header.liquid +26 -0
  57. package/deps/jq/exec_stack.h +112 -0
  58. package/deps/jq/execute.c +1155 -0
  59. package/deps/jq/inject_errors.c +112 -0
  60. package/deps/jq/jq.1.default +39 -0
  61. package/deps/jq/jq.1.prebuilt +3075 -0
  62. package/deps/jq/jq.h +60 -0
  63. package/deps/jq/jq.spec +70 -0
  64. package/deps/jq/jq_parser.h +9 -0
  65. package/deps/jq/jq_test.c +346 -0
  66. package/deps/jq/jv.c +1333 -0
  67. package/deps/jq/jv.h +240 -0
  68. package/deps/jq/jv_alloc.c +179 -0
  69. package/deps/jq/jv_alloc.h +27 -0
  70. package/deps/jq/jv_aux.c +619 -0
  71. package/deps/jq/jv_dtoa.c +4275 -0
  72. package/deps/jq/jv_dtoa.h +22 -0
  73. package/deps/jq/jv_file.c +49 -0
  74. package/deps/jq/jv_parse.c +852 -0
  75. package/deps/jq/jv_print.c +348 -0
  76. package/deps/jq/jv_unicode.c +96 -0
  77. package/deps/jq/jv_unicode.h +11 -0
  78. package/deps/jq/jv_utf8_tables.h +37 -0
  79. package/deps/jq/lexer.c +2442 -0
  80. package/deps/jq/lexer.h +362 -0
  81. package/deps/jq/lexer.l +184 -0
  82. package/deps/jq/libm.h +160 -0
  83. package/deps/jq/linker.c +393 -0
  84. package/deps/jq/linker.h +7 -0
  85. package/deps/jq/locfile.c +91 -0
  86. package/deps/jq/locfile.h +29 -0
  87. package/deps/jq/m4/ax_compare_version.m4 +177 -0
  88. package/deps/jq/m4/ax_prog_bison_version.m4 +68 -0
  89. package/deps/jq/main.c +566 -0
  90. package/deps/jq/opcode_list.h +44 -0
  91. package/deps/jq/parser.c +3914 -0
  92. package/deps/jq/parser.h +193 -0
  93. package/deps/jq/parser.y +923 -0
  94. package/deps/jq/scripts/crosscompile +42 -0
  95. package/deps/jq/scripts/gen_utf8_tables.py +32 -0
  96. package/deps/jq/scripts/version +5 -0
  97. package/deps/jq/setup.sh +33 -0
  98. package/deps/jq/tests/jq.test +1235 -0
  99. package/deps/jq/tests/jqtest +5 -0
  100. package/deps/jq/tests/mantest +7 -0
  101. package/deps/jq/tests/modules/.jq +5 -0
  102. package/deps/jq/tests/modules/a.jq +2 -0
  103. package/deps/jq/tests/modules/b/b.jq +2 -0
  104. package/deps/jq/tests/modules/c/c.jq +16 -0
  105. package/deps/jq/tests/modules/c/d.jq +1 -0
  106. package/deps/jq/tests/modules/data.json +4 -0
  107. package/deps/jq/tests/modules/lib/jq/e/e.jq +1 -0
  108. package/deps/jq/tests/modules/lib/jq/f.jq +1 -0
  109. package/deps/jq/tests/modules/syntaxerror/syntaxerror.jq +1 -0
  110. package/deps/jq/tests/modules/test_bind_order.jq +4 -0
  111. package/deps/jq/tests/modules/test_bind_order0.jq +1 -0
  112. package/deps/jq/tests/modules/test_bind_order1.jq +2 -0
  113. package/deps/jq/tests/modules/test_bind_order2.jq +2 -0
  114. package/deps/jq/tests/onig.supp +21 -0
  115. package/deps/jq/tests/onig.test +85 -0
  116. package/deps/jq/tests/onigtest +5 -0
  117. package/deps/jq/tests/setup +36 -0
  118. package/deps/jq/tests/shtest +205 -0
  119. package/deps/jq/tests/torture/input0.json +7 -0
  120. package/deps/jq/util.c +462 -0
  121. package/deps/jq/util.h +64 -0
  122. package/deps/jq.gyp +35 -0
  123. package/index.d.ts +3 -0
  124. package/jest.config.js +10 -0
  125. package/lib/index.js +14 -0
  126. package/package.json +48 -0
  127. package/reports/jest-port-api.xml +35 -0
  128. package/src/binding.cc +177 -0
  129. package/src/binding.h +13 -0
  130. package/test/santiy.test.js +122 -0
  131. package/util/configure.js +27 -0
@@ -0,0 +1,1210 @@
1
+ #ifndef _GNU_SOURCE
2
+ #define _GNU_SOURCE // for strdup
3
+ #endif
4
+ #include <assert.h>
5
+ #include <math.h>
6
+ #include <string.h>
7
+ #include <stdlib.h>
8
+ #include "compile.h"
9
+ #include "bytecode.h"
10
+ #include "locfile.h"
11
+ #include "jv_alloc.h"
12
+ #include "linker.h"
13
+
14
+ /*
15
+ The intermediate representation for jq filters is as a sequence of
16
+ struct inst, which form a doubly-linked list via the next and prev
17
+ pointers.
18
+
19
+ A "block" represents a sequence of "struct inst", which may be
20
+ empty.
21
+
22
+ Blocks are generated by the parser bottom-up, so may have free
23
+ variables (refer to things not defined). See inst.bound_by and
24
+ inst.symbol.
25
+ */
26
+ struct inst {
27
+ struct inst* next;
28
+ struct inst* prev;
29
+
30
+ opcode op;
31
+
32
+ struct {
33
+ uint16_t intval;
34
+ struct inst* target;
35
+ jv constant;
36
+ const struct cfunction* cfunc;
37
+ } imm;
38
+
39
+ struct locfile* locfile;
40
+ location source;
41
+
42
+ // Binding
43
+ // An instruction requiring binding (for parameters/variables/functions)
44
+ // is in one of three states:
45
+ // inst->bound_by = NULL - Unbound free variable
46
+ // inst->bound_by = inst - This instruction binds a variable
47
+ // inst->bound_by = other - Uses variable bound by other instruction
48
+ // Unbound instructions (references to other things that may or may not
49
+ // exist) are created by "gen_foo_unbound", and bindings are created by
50
+ // block_bind(definition, body), which binds all instructions in
51
+ // body which are unboudn and refer to "definition" by name.
52
+ struct inst* bound_by;
53
+ char* symbol;
54
+
55
+ int nformals;
56
+ int nactuals;
57
+
58
+ block subfn; // used by CLOSURE_CREATE (body of function)
59
+ block arglist; // used by CLOSURE_CREATE (formals) and CALL_JQ (arguments)
60
+
61
+ // This instruction is compiled as part of which function?
62
+ // (only used during block_compile)
63
+ struct bytecode* compiled;
64
+
65
+ int bytecode_pos; // position just after this insn
66
+ };
67
+
68
+ static inst* inst_new(opcode op) {
69
+ inst* i = jv_mem_alloc(sizeof(inst));
70
+ i->next = i->prev = 0;
71
+ i->op = op;
72
+ i->bytecode_pos = -1;
73
+ i->bound_by = 0;
74
+ i->symbol = 0;
75
+ i->nformals = -1;
76
+ i->nactuals = -1;
77
+ i->subfn = gen_noop();
78
+ i->arglist = gen_noop();
79
+ i->source = UNKNOWN_LOCATION;
80
+ i->locfile = 0;
81
+ return i;
82
+ }
83
+
84
+ static void inst_free(struct inst* i) {
85
+ jv_mem_free(i->symbol);
86
+ block_free(i->subfn);
87
+ block_free(i->arglist);
88
+ if (i->locfile)
89
+ locfile_free(i->locfile);
90
+ if (opcode_describe(i->op)->flags & OP_HAS_CONSTANT) {
91
+ jv_free(i->imm.constant);
92
+ }
93
+ jv_mem_free(i);
94
+ }
95
+
96
+ static block inst_block(inst* i) {
97
+ block b = {i,i};
98
+ return b;
99
+ }
100
+
101
+ int block_is_single(block b) {
102
+ return b.first && b.first == b.last;
103
+ }
104
+
105
+ static inst* block_take(block* b) {
106
+ if (b->first == 0) return 0;
107
+ inst* i = b->first;
108
+ if (i->next) {
109
+ i->next->prev = 0;
110
+ b->first = i->next;
111
+ i->next = 0;
112
+ } else {
113
+ b->first = 0;
114
+ b->last = 0;
115
+ }
116
+ return i;
117
+ }
118
+
119
+ block gen_location(location loc, struct locfile* l, block b) {
120
+ for (inst* i = b.first; i; i = i->next) {
121
+ if (i->source.start == UNKNOWN_LOCATION.start &&
122
+ i->source.end == UNKNOWN_LOCATION.end) {
123
+ i->source = loc;
124
+ i->locfile = locfile_retain(l);
125
+ }
126
+ }
127
+ return b;
128
+ }
129
+
130
+ block gen_noop() {
131
+ block b = {0,0};
132
+ return b;
133
+ }
134
+
135
+ int block_is_noop(block b) {
136
+ return (b.first == 0 && b.last == 0);
137
+ }
138
+
139
+ block gen_op_simple(opcode op) {
140
+ assert(opcode_describe(op)->length == 1);
141
+ return inst_block(inst_new(op));
142
+ }
143
+
144
+
145
+ block gen_const(jv constant) {
146
+ assert(opcode_describe(LOADK)->flags & OP_HAS_CONSTANT);
147
+ inst* i = inst_new(LOADK);
148
+ i->imm.constant = constant;
149
+ return inst_block(i);
150
+ }
151
+
152
+ block gen_const_global(jv constant, const char *name) {
153
+ assert((opcode_describe(STORE_GLOBAL)->flags & (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING)) ==
154
+ (OP_HAS_CONSTANT | OP_HAS_VARIABLE | OP_HAS_BINDING));
155
+ inst* i = inst_new(STORE_GLOBAL);
156
+ i->imm.constant = constant;
157
+ i->symbol = strdup(name);
158
+ return inst_block(i);
159
+ }
160
+
161
+ int block_is_const(block b) {
162
+ return (block_is_single(b) && b.first->op == LOADK);
163
+ }
164
+
165
+ int block_is_const_inf(block b) {
166
+ return (block_is_single(b) && b.first->op == LOADK &&
167
+ jv_get_kind(b.first->imm.constant) == JV_KIND_NUMBER &&
168
+ isinf(jv_number_value(b.first->imm.constant)));
169
+ }
170
+
171
+ jv_kind block_const_kind(block b) {
172
+ assert(block_is_const(b));
173
+ return jv_get_kind(b.first->imm.constant);
174
+ }
175
+
176
+ jv block_const(block b) {
177
+ assert(block_is_const(b));
178
+ return jv_copy(b.first->imm.constant);
179
+ }
180
+
181
+ block gen_op_target(opcode op, block target) {
182
+ assert(opcode_describe(op)->flags & OP_HAS_BRANCH);
183
+ assert(target.last);
184
+ inst* i = inst_new(op);
185
+ i->imm.target = target.last;
186
+ return inst_block(i);
187
+ }
188
+
189
+ block gen_op_targetlater(opcode op) {
190
+ assert(opcode_describe(op)->flags & OP_HAS_BRANCH);
191
+ inst* i = inst_new(op);
192
+ i->imm.target = 0;
193
+ return inst_block(i);
194
+ }
195
+ void inst_set_target(block b, block target) {
196
+ assert(block_is_single(b));
197
+ assert(opcode_describe(b.first->op)->flags & OP_HAS_BRANCH);
198
+ assert(target.last);
199
+ b.first->imm.target = target.last;
200
+ }
201
+
202
+ block gen_op_unbound(opcode op, const char* name) {
203
+ assert(opcode_describe(op)->flags & OP_HAS_BINDING);
204
+ inst* i = inst_new(op);
205
+ i->symbol = strdup(name);
206
+ return inst_block(i);
207
+ }
208
+
209
+ block gen_op_var_fresh(opcode op, const char* name) {
210
+ assert(opcode_describe(op)->flags & OP_HAS_VARIABLE);
211
+ return block_bind(gen_op_unbound(op, name),
212
+ gen_noop(), OP_HAS_VARIABLE);
213
+ }
214
+
215
+ block gen_op_bound(opcode op, block binder) {
216
+ assert(block_is_single(binder));
217
+ block b = gen_op_unbound(op, binder.first->symbol);
218
+ b.first->bound_by = binder.first;
219
+ return b;
220
+ }
221
+
222
+
223
+ static void inst_join(inst* a, inst* b) {
224
+ assert(a && b);
225
+ assert(!a->next);
226
+ assert(!b->prev);
227
+ a->next = b;
228
+ b->prev = a;
229
+ }
230
+
231
+ void block_append(block* b, block b2) {
232
+ if (b2.first) {
233
+ if (b->last) {
234
+ inst_join(b->last, b2.first);
235
+ } else {
236
+ b->first = b2.first;
237
+ }
238
+ b->last = b2.last;
239
+ }
240
+ }
241
+
242
+ block block_join(block a, block b) {
243
+ block c = a;
244
+ block_append(&c, b);
245
+ return c;
246
+ }
247
+
248
+ int block_has_only_binders_and_imports(block binders, int bindflags) {
249
+ bindflags |= OP_HAS_BINDING;
250
+ for (inst* curr = binders.first; curr; curr = curr->next) {
251
+ if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != DEPS && curr->op != MODULEMETA) {
252
+ return 0;
253
+ }
254
+ }
255
+ return 1;
256
+ }
257
+
258
+ static int inst_is_binder(inst *i, int bindflags) {
259
+ return !((opcode_describe(i->op)->flags & bindflags) != bindflags && i->op != MODULEMETA);
260
+ }
261
+
262
+ int block_has_only_binders(block binders, int bindflags) {
263
+ bindflags |= OP_HAS_BINDING;
264
+ bindflags &= ~OP_BIND_WILDCARD;
265
+ for (inst* curr = binders.first; curr; curr = curr->next) {
266
+ if ((opcode_describe(curr->op)->flags & bindflags) != bindflags && curr->op != MODULEMETA) {
267
+ return 0;
268
+ }
269
+ }
270
+ return 1;
271
+ }
272
+
273
+ // Count a binder's (function) formal params
274
+ static int block_count_formals(block b) {
275
+ int args = 0;
276
+ if (b.first->op == CLOSURE_CREATE_C)
277
+ return b.first->imm.cfunc->nargs - 1;
278
+ for (inst* i = b.first->arglist.first; i; i = i->next) {
279
+ assert(i->op == CLOSURE_PARAM);
280
+ args++;
281
+ }
282
+ return args;
283
+ }
284
+
285
+ // Count a call site's actual params
286
+ static int block_count_actuals(block b) {
287
+ int args = 0;
288
+ for (inst* i = b.first; i; i = i->next) {
289
+ switch (i->op) {
290
+ default: assert(0 && "Unknown function type"); break;
291
+ case CLOSURE_CREATE:
292
+ case CLOSURE_PARAM:
293
+ case CLOSURE_CREATE_C:
294
+ args++;
295
+ break;
296
+ }
297
+ }
298
+ return args;
299
+ }
300
+
301
+ static int block_count_refs(block binder, block body) {
302
+ int nrefs = 0;
303
+ for (inst* i = body.first; i; i = i->next) {
304
+ if (i != binder.first && i->bound_by == binder.first) {
305
+ nrefs++;
306
+ }
307
+ // counting recurses into closures
308
+ nrefs += block_count_refs(binder, i->subfn);
309
+ // counting recurses into argument list
310
+ nrefs += block_count_refs(binder, i->arglist);
311
+ }
312
+ return nrefs;
313
+ }
314
+
315
+ static int block_bind_subblock(block binder, block body, int bindflags, int break_distance) {
316
+ assert(block_is_single(binder));
317
+ assert((opcode_describe(binder.first->op)->flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD));
318
+ assert(binder.first->symbol);
319
+ assert(binder.first->bound_by == 0 || binder.first->bound_by == binder.first);
320
+ assert(break_distance >= 0);
321
+
322
+ binder.first->bound_by = binder.first;
323
+ if (binder.first->nformals == -1)
324
+ binder.first->nformals = block_count_formals(binder);
325
+ int nrefs = 0;
326
+ for (inst* i = body.first; i; i = i->next) {
327
+ int flags = opcode_describe(i->op)->flags;
328
+ if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by == 0 &&
329
+ (!strcmp(i->symbol, binder.first->symbol) ||
330
+ // Check for break/break2/break3; see parser.y
331
+ ((bindflags & OP_BIND_WILDCARD) && i->symbol[0] == '*' &&
332
+ break_distance <= 3 && (i->symbol[1] == '1' + break_distance) &&
333
+ i->symbol[2] == '\0'))) {
334
+ // bind this instruction
335
+ if (i->op == CALL_JQ && i->nactuals == -1)
336
+ i->nactuals = block_count_actuals(i->arglist);
337
+ if (i->nactuals == -1 || i->nactuals == binder.first->nformals) {
338
+ i->bound_by = binder.first;
339
+ nrefs++;
340
+ }
341
+ } else if ((flags & bindflags) == (bindflags & ~OP_BIND_WILDCARD) && i->bound_by != 0 &&
342
+ !strncmp(binder.first->symbol, "*anonlabel", sizeof("*anonlabel") - 1) &&
343
+ !strncmp(i->symbol, "*anonlabel", sizeof("*anonlabel") - 1)) {
344
+ // Increment the break distance required for this binder to match
345
+ // a break whenever we come across a STOREV of *anonlabel...
346
+ break_distance++;
347
+ }
348
+ // binding recurses into closures
349
+ nrefs += block_bind_subblock(binder, i->subfn, bindflags, break_distance);
350
+ // binding recurses into argument list
351
+ nrefs += block_bind_subblock(binder, i->arglist, bindflags, break_distance);
352
+ }
353
+ return nrefs;
354
+ }
355
+
356
+ static int block_bind_each(block binder, block body, int bindflags) {
357
+ assert(block_has_only_binders(binder, bindflags));
358
+ bindflags |= OP_HAS_BINDING;
359
+ int nrefs = 0;
360
+ for (inst* curr = binder.first; curr; curr = curr->next) {
361
+ nrefs += block_bind_subblock(inst_block(curr), body, bindflags, 0);
362
+ }
363
+ return nrefs;
364
+ }
365
+
366
+ block block_bind(block binder, block body, int bindflags) {
367
+ block_bind_each(binder, body, bindflags);
368
+ return block_join(binder, body);
369
+ }
370
+
371
+ block block_bind_library(block binder, block body, int bindflags, const char *libname) {
372
+ bindflags |= OP_HAS_BINDING;
373
+ int nrefs = 0;
374
+ int matchlen = (libname == NULL) ? 0 : strlen(libname);
375
+ char *matchname = jv_mem_alloc(matchlen+2+1);
376
+ matchname[0] = '\0';
377
+ if (libname != NULL && libname[0] != '\0') {
378
+ strcpy(matchname,libname);
379
+ strcpy(matchname+matchlen, "::");
380
+ matchlen += 2;
381
+ }
382
+ assert(block_has_only_binders(binder, bindflags));
383
+ for (inst *curr = binder.first; curr; curr = curr->next) {
384
+ int bindflags2 = bindflags;
385
+ char* cname = curr->symbol;
386
+ char* tname = jv_mem_alloc(strlen(curr->symbol)+matchlen+1);
387
+ strcpy(tname, matchname);
388
+ strcpy(tname+matchlen, curr->symbol);
389
+
390
+ // Ew
391
+ if ((opcode_describe(curr->op)->flags & (OP_HAS_VARIABLE | OP_HAS_CONSTANT)))
392
+ bindflags2 = OP_HAS_VARIABLE | OP_HAS_BINDING;
393
+
394
+ // This mutation is ugly, even if we undo it
395
+ curr->symbol = tname;
396
+ nrefs += block_bind_subblock(inst_block(curr), body, bindflags2, 0);
397
+ curr->symbol = cname;
398
+ free(tname);
399
+ }
400
+ free(matchname);
401
+ return body; // We don't return a join because we don't want those sticking around...
402
+ }
403
+
404
+ // Bind binder to body and throw away any defs in binder not referenced
405
+ // (directly or indirectly) from body.
406
+ block block_bind_referenced(block binder, block body, int bindflags) {
407
+ assert(block_has_only_binders(binder, bindflags));
408
+ bindflags |= OP_HAS_BINDING;
409
+ block refd = gen_noop();
410
+ block unrefd = gen_noop();
411
+ int nrefs;
412
+ for (int last_kept = 0, kept = 0; ; ) {
413
+ for (inst* curr; (curr = block_take(&binder));) {
414
+ block b = inst_block(curr);
415
+ nrefs = block_bind_each(b, body, bindflags);
416
+ // Check if this binder is referenced from any of the ones we
417
+ // already know are referenced by body.
418
+ nrefs += block_count_refs(b, refd);
419
+ nrefs += block_count_refs(b, body);
420
+ if (nrefs) {
421
+ refd = BLOCK(refd, b);
422
+ kept++;
423
+ } else {
424
+ unrefd = BLOCK(unrefd, b);
425
+ }
426
+ }
427
+ if (kept == last_kept)
428
+ break;
429
+ last_kept = kept;
430
+ binder = unrefd;
431
+ unrefd = gen_noop();
432
+ }
433
+ block_free(unrefd);
434
+ return block_join(refd, body);
435
+ }
436
+
437
+ block block_drop_unreferenced(block body) {
438
+ inst* curr;
439
+ block refd = gen_noop();
440
+ block unrefd = gen_noop();
441
+ int drop;
442
+ do {
443
+ drop = 0;
444
+ while ((curr = block_take(&body)) && curr->op != TOP) {
445
+ block b = inst_block(curr);
446
+ if (block_count_refs(b,refd) + block_count_refs(b,body) == 0) {
447
+ unrefd = BLOCK(unrefd, b);
448
+ drop++;
449
+ } else {
450
+ refd = BLOCK(refd, b);
451
+ }
452
+ }
453
+ if (curr && curr->op == TOP) {
454
+ body = BLOCK(inst_block(curr),body);
455
+ }
456
+ body = BLOCK(refd, body);
457
+ refd = gen_noop();
458
+ } while (drop != 0);
459
+ block_free(unrefd);
460
+ return body;
461
+ }
462
+
463
+ jv block_take_imports(block* body) {
464
+ jv imports = jv_array();
465
+
466
+ inst* top = NULL;
467
+ if (body->first && body->first->op == TOP) {
468
+ top = block_take(body);
469
+ }
470
+ while (body->first && (body->first->op == MODULEMETA || body->first->op == DEPS)) {
471
+ inst* dep = block_take(body);
472
+ if (dep->op == DEPS) {
473
+ imports = jv_array_append(imports, jv_copy(dep->imm.constant));
474
+ }
475
+ inst_free(dep);
476
+ }
477
+ if (top) {
478
+ *body = block_join(inst_block(top),*body);
479
+ }
480
+ return imports;
481
+ }
482
+
483
+ block gen_module(block metadata) {
484
+ inst* i = inst_new(MODULEMETA);
485
+ i->imm.constant = block_const(metadata);
486
+ if (jv_get_kind(i->imm.constant) != JV_KIND_OBJECT)
487
+ i->imm.constant = jv_object_set(jv_object(), jv_string("metadata"), i->imm.constant);
488
+ block_free(metadata);
489
+ return inst_block(i);
490
+ }
491
+
492
+ jv block_module_meta(block b) {
493
+ if (b.first != NULL && b.first->op == MODULEMETA)
494
+ return jv_copy(b.first->imm.constant);
495
+ return jv_null();
496
+ }
497
+
498
+ block gen_import(const char* name, block metadata, const char* as, int is_data) {
499
+ assert(metadata.first == NULL || block_is_const(metadata));
500
+ inst* i = inst_new(DEPS);
501
+ jv meta;
502
+ if (block_is_const(metadata))
503
+ meta = block_const(metadata);
504
+ else
505
+ meta = jv_object();
506
+ if (as != NULL)
507
+ meta = jv_object_set(meta, jv_string("as"), jv_string(as));
508
+ meta = jv_object_set(meta, jv_string("is_data"), is_data ? jv_true() : jv_false());
509
+ meta = jv_object_set(meta, jv_string("relpath"), jv_string(name));
510
+ i->imm.constant = meta;
511
+ block_free(metadata);
512
+ return inst_block(i);
513
+ }
514
+
515
+ block gen_function(const char* name, block formals, block body) {
516
+ inst* i = inst_new(CLOSURE_CREATE);
517
+ for (inst* i = formals.last; i; i = i->prev) {
518
+ if (i->op == CLOSURE_PARAM_REGULAR) {
519
+ i->op = CLOSURE_PARAM;
520
+ body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body);
521
+ }
522
+ block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0);
523
+ }
524
+ i->subfn = body;
525
+ i->symbol = strdup(name);
526
+ i->arglist = formals;
527
+ block b = inst_block(i);
528
+ block_bind_subblock(b, b, OP_IS_CALL_PSEUDO | OP_HAS_BINDING, 0);
529
+ return b;
530
+ }
531
+
532
+ block gen_param_regular(const char* name) {
533
+ return gen_op_unbound(CLOSURE_PARAM_REGULAR, name);
534
+ }
535
+
536
+ block gen_param(const char* name) {
537
+ return gen_op_unbound(CLOSURE_PARAM, name);
538
+ }
539
+
540
+ block gen_lambda(block body) {
541
+ return gen_function("@lambda", gen_noop(), body);
542
+ }
543
+
544
+ block gen_call(const char* name, block args) {
545
+ block b = gen_op_unbound(CALL_JQ, name);
546
+ b.first->arglist = args;
547
+ return b;
548
+ }
549
+
550
+
551
+
552
+ block gen_subexp(block a) {
553
+ return BLOCK(gen_op_simple(SUBEXP_BEGIN), a, gen_op_simple(SUBEXP_END));
554
+ }
555
+
556
+ block gen_both(block a, block b) {
557
+ block jump = gen_op_targetlater(JUMP);
558
+ block fork = gen_op_target(FORK, jump);
559
+ block c = BLOCK(fork, a, jump, b);
560
+ inst_set_target(jump, c);
561
+ return c;
562
+ }
563
+
564
+ block gen_const_object(block expr) {
565
+ int is_const = 1;
566
+ jv o = jv_object();
567
+ jv k = jv_null();
568
+ jv v = jv_null();
569
+ for (inst *i = expr.first; i; i = i->next) {
570
+ if (i->op != SUBEXP_BEGIN ||
571
+ i->next == NULL ||
572
+ i->next->op != LOADK ||
573
+ i->next->next == NULL ||
574
+ i->next->next->op != SUBEXP_END) {
575
+ is_const = 0;
576
+ break;
577
+ }
578
+ k = jv_copy(i->next->imm.constant);
579
+ i = i->next->next->next;
580
+ if (i == NULL ||
581
+ i->op != SUBEXP_BEGIN ||
582
+ i->next == NULL ||
583
+ i->next->op != LOADK ||
584
+ i->next->next == NULL ||
585
+ i->next->next->op != SUBEXP_END) {
586
+ is_const = 0;
587
+ break;
588
+ }
589
+ v = jv_copy(i->next->imm.constant);
590
+ i = i->next->next->next;
591
+ if (i == NULL || i->op != INSERT) {
592
+ is_const = 0;
593
+ break;
594
+ }
595
+ o = jv_object_set(o, k, v);
596
+ k = jv_null();
597
+ v = jv_null();
598
+ }
599
+ if (!is_const) {
600
+ jv_free(o);
601
+ jv_free(k);
602
+ jv_free(v);
603
+ block b = {0,0};
604
+ return b;
605
+ }
606
+ block_free(expr);
607
+ return gen_const(o);
608
+ }
609
+
610
+ static block gen_const_array(block expr) {
611
+ /*
612
+ * An expr of all constant elements looks like this:
613
+ *
614
+ * 0009 FORK 0027
615
+ * 0011 FORK 0023
616
+ * 0013 FORK 0019
617
+ * 0015 LOADK 1
618
+ * 0017 JUMP 0021
619
+ * 0019 LOADK 2
620
+ * 0021 JUMP 0025
621
+ * 0023 LOADK 3
622
+ * 0025 JUMP 0029
623
+ * 0027 LOADK 4
624
+ *
625
+ * That's: N-1 commas for N elements, N LOADKs, and a JUMP between
626
+ * every LOADK. The sequence ends in a LOADK. Any deviation and it's
627
+ * not a list of constants.
628
+ *
629
+ * Here we check for this pattern almost exactly. We don't check that
630
+ * the targets of the FORK and JUMP instructions are in the right
631
+ * sequence.
632
+ */
633
+ int all_const = 1;
634
+ int commas = 0;
635
+ int normal = 1;
636
+ jv a = jv_array();
637
+ for (inst *i = expr.first; i; i = i->next) {
638
+ if (i->op == FORK) {
639
+ commas++;
640
+ if (i->imm.target == NULL || i->imm.target->op != JUMP ||
641
+ jv_array_length(jv_copy(a)) > 0) {
642
+ normal = 0;
643
+ break;
644
+ }
645
+ } else if (all_const && i->op == LOADK) {
646
+ if (i->next != NULL && i->next->op != JUMP) {
647
+ normal = 0;
648
+ break;
649
+ }
650
+ a = jv_array_append(a, jv_copy(i->imm.constant));
651
+ } else if (i->op != JUMP || i->imm.target == NULL ||
652
+ i->imm.target->op != LOADK) {
653
+ all_const = 0;
654
+ }
655
+ }
656
+
657
+ if (all_const && normal &&
658
+ (expr.last == NULL || expr.last->op == LOADK) &&
659
+ jv_array_length(jv_copy(a)) == commas + 1) {
660
+ block_free(expr);
661
+ return gen_const(a);
662
+ }
663
+
664
+ jv_free(a);
665
+ block b = {0,0};
666
+ return b;
667
+ }
668
+
669
+ block gen_collect(block expr) {
670
+ block const_array = gen_const_array(expr);
671
+ if (const_array.first != NULL)
672
+ return const_array;
673
+
674
+ block array_var = gen_op_var_fresh(STOREV, "collect");
675
+ block c = BLOCK(gen_op_simple(DUP), gen_const(jv_array()), array_var);
676
+
677
+ block tail = BLOCK(gen_op_bound(APPEND, array_var),
678
+ gen_op_simple(BACKTRACK));
679
+
680
+ return BLOCK(c,
681
+ gen_op_target(FORK, tail),
682
+ expr,
683
+ tail,
684
+ gen_op_bound(LOADVN, array_var));
685
+ }
686
+
687
+ static block bind_matcher(block matcher, block body) {
688
+ // cannot call block_bind(matcher, body) because that requires
689
+ // block_has_only_binders(matcher), which is not true here as matchers
690
+ // may also contain code to extract the correct elements
691
+ for (inst* i = matcher.first; i; i = i->next) {
692
+ if (i->op == STOREV && !i->bound_by)
693
+ block_bind_subblock(inst_block(i), body, OP_HAS_VARIABLE, 0);
694
+ }
695
+ return BLOCK(matcher, body);
696
+ }
697
+
698
+ block gen_reduce(block source, block matcher, block init, block body) {
699
+ block res_var = gen_op_var_fresh(STOREV, "reduce");
700
+ block loop = BLOCK(gen_op_simple(DUPN),
701
+ source,
702
+ bind_matcher(matcher,
703
+ BLOCK(gen_op_bound(LOADVN, res_var),
704
+ body,
705
+ gen_op_bound(STOREV, res_var))),
706
+ gen_op_simple(BACKTRACK));
707
+ return BLOCK(gen_op_simple(DUP),
708
+ init,
709
+ res_var,
710
+ gen_op_target(FORK, loop),
711
+ loop,
712
+ gen_op_bound(LOADVN, res_var));
713
+ }
714
+
715
+ block gen_foreach(block source, block matcher, block init, block update, block extract) {
716
+ block output = gen_op_targetlater(JUMP);
717
+ block state_var = gen_op_var_fresh(STOREV, "foreach");
718
+ block loop = BLOCK(gen_op_simple(DUPN),
719
+ // get a value from the source expression:
720
+ source,
721
+ // destructure the value into variable(s) for all the code
722
+ // in the body to see
723
+ bind_matcher(matcher,
724
+ // load the loop state variable
725
+ BLOCK(gen_op_bound(LOADVN, state_var),
726
+ // generate updated state
727
+ update,
728
+ // save the updated state for value extraction
729
+ gen_op_simple(DUP),
730
+ // save new state
731
+ gen_op_bound(STOREV, state_var),
732
+ // extract an output...
733
+ extract,
734
+ // ...and output it by jumping
735
+ // past the BACKTRACK that comes
736
+ // right after the loop body,
737
+ // which in turn is there
738
+ // because...
739
+ //
740
+ // (Incidentally, extract can also
741
+ // backtrack, e.g., if it calls
742
+ // empty, in which case we don't
743
+ // get here.)
744
+ output)));
745
+ block foreach = BLOCK(gen_op_simple(DUP),
746
+ init,
747
+ state_var,
748
+ gen_op_target(FORK, loop),
749
+ loop,
750
+ // ...at this point `foreach`'s original input
751
+ // will be on top of the stack, and we don't
752
+ // want to output it, so we backtrack.
753
+ gen_op_simple(BACKTRACK));
754
+ inst_set_target(output, foreach); // make that JUMP go bast the BACKTRACK at the end of the loop
755
+ return foreach;
756
+ }
757
+
758
+ block gen_definedor(block a, block b) {
759
+ // var found := false
760
+ block found_var = gen_op_var_fresh(STOREV, "found");
761
+ block init = BLOCK(gen_op_simple(DUP), gen_const(jv_false()), found_var);
762
+
763
+ // if found, backtrack. Otherwise execute b
764
+ block backtrack = gen_op_simple(BACKTRACK);
765
+ block tail = BLOCK(gen_op_simple(DUP),
766
+ gen_op_bound(LOADV, found_var),
767
+ gen_op_target(JUMP_F, backtrack),
768
+ backtrack,
769
+ gen_op_simple(POP),
770
+ b);
771
+
772
+ // try again
773
+ block if_notfound = gen_op_simple(BACKTRACK);
774
+
775
+ // found := true, produce result
776
+ block if_found = BLOCK(gen_op_simple(DUP),
777
+ gen_const(jv_true()),
778
+ gen_op_bound(STOREV, found_var),
779
+ gen_op_target(JUMP, tail));
780
+
781
+ return BLOCK(init,
782
+ gen_op_target(FORK, if_notfound),
783
+ a,
784
+ gen_op_target(JUMP_F, if_found),
785
+ if_found,
786
+ if_notfound,
787
+ tail);
788
+ }
789
+
790
+ int block_has_main(block top) {
791
+ for (inst *c = top.first; c; c = c->next) {
792
+ if (c->op == TOP)
793
+ return 1;
794
+ }
795
+ return 0;
796
+ }
797
+
798
+ int block_is_funcdef(block b) {
799
+ if (b.first != NULL && b.first->op == CLOSURE_CREATE)
800
+ return 1;
801
+ return 0;
802
+ }
803
+
804
+ block gen_condbranch(block iftrue, block iffalse) {
805
+ iftrue = BLOCK(iftrue, gen_op_target(JUMP, iffalse));
806
+ return BLOCK(gen_op_target(JUMP_F, iftrue), iftrue, iffalse);
807
+ }
808
+
809
+ block gen_and(block a, block b) {
810
+ // a and b = if a then (if b then true else false) else false
811
+ return BLOCK(gen_op_simple(DUP), a,
812
+ gen_condbranch(BLOCK(gen_op_simple(POP),
813
+ b,
814
+ gen_condbranch(gen_const(jv_true()),
815
+ gen_const(jv_false()))),
816
+ BLOCK(gen_op_simple(POP), gen_const(jv_false()))));
817
+ }
818
+
819
+ block gen_or(block a, block b) {
820
+ // a or b = if a then true else (if b then true else false)
821
+ return BLOCK(gen_op_simple(DUP), a,
822
+ gen_condbranch(BLOCK(gen_op_simple(POP), gen_const(jv_true())),
823
+ BLOCK(gen_op_simple(POP),
824
+ b,
825
+ gen_condbranch(gen_const(jv_true()),
826
+ gen_const(jv_false())))));
827
+ }
828
+
829
+ block gen_var_binding(block var, const char* name, block body) {
830
+ return gen_destructure(var, gen_op_unbound(STOREV, name), body);
831
+ }
832
+
833
+ block gen_array_matcher(block left, block curr) {
834
+ int index;
835
+ if (block_is_noop(left))
836
+ index = 0;
837
+ else {
838
+ // `left` was returned by this function, so the third inst is the
839
+ // constant containing the previously used index
840
+ assert(left.first->op == DUP);
841
+ assert(left.first->next->op == SUBEXP_BEGIN);
842
+ assert(left.first->next->next->op == LOADK);
843
+ index = 1 + (int) jv_number_value(left.first->next->next->imm.constant);
844
+ }
845
+
846
+ // `left` goes at the end so that the const index is in a predictable place
847
+ return BLOCK(gen_op_simple(DUP), gen_subexp(gen_const(jv_number(index))),
848
+ gen_op_simple(INDEX), curr, left);
849
+ }
850
+
851
+ block gen_object_matcher(block name, block curr) {
852
+ return BLOCK(gen_op_simple(DUP), gen_subexp(name), gen_op_simple(INDEX),
853
+ curr);
854
+ }
855
+
856
+ block gen_destructure(block var, block matcher, block body) {
857
+ // var bindings can be added after coding the program; leave the TOP first.
858
+ block top = gen_noop();
859
+ if (body.first && body.first->op == TOP)
860
+ top = inst_block(block_take(&body));
861
+
862
+ return BLOCK(top, gen_op_simple(DUP), var, bind_matcher(matcher, body));
863
+ }
864
+
865
+ // Like gen_var_binding(), but bind `break`'s wildcard unbound variable
866
+ static block gen_wildvar_binding(block var, const char* name, block body) {
867
+ return BLOCK(gen_op_simple(DUP), var,
868
+ block_bind(gen_op_unbound(STOREV, name),
869
+ body, OP_HAS_VARIABLE | OP_BIND_WILDCARD));
870
+ }
871
+
872
+ block gen_cond(block cond, block iftrue, block iffalse) {
873
+ return BLOCK(gen_op_simple(DUP), cond,
874
+ gen_condbranch(BLOCK(gen_op_simple(POP), iftrue),
875
+ BLOCK(gen_op_simple(POP), iffalse)));
876
+ }
877
+
878
+ block gen_try_handler(block handler) {
879
+ // Quite a pain just to hide jq's internal errors.
880
+ return gen_cond(// `if type=="object" and .__jq
881
+ gen_and(gen_call("_equal",
882
+ BLOCK(gen_lambda(gen_const(jv_string("object"))),
883
+ gen_lambda(gen_noop()))),
884
+ BLOCK(gen_subexp(gen_const(jv_string("__jq"))),
885
+ gen_noop(),
886
+ gen_op_simple(INDEX))),
887
+ // `then error`
888
+ gen_call("error", gen_noop()),
889
+ // `else HANDLER end`
890
+ handler);
891
+ }
892
+
893
+ block gen_try(block exp, block handler) {
894
+ /*
895
+ * Produce something like:
896
+ * FORK_OPT <address of handler>
897
+ * <exp>
898
+ * JUMP <end of handler>
899
+ * <handler>
900
+ *
901
+ * If this is not an internal try/catch, then catch and re-raise
902
+ * internal errors to prevent them from leaking.
903
+ *
904
+ * The handler will only execute if we backtrack to the FORK_OPT with
905
+ * an error (exception). If <exp> produces no value then FORK_OPT
906
+ * will backtrack (propagate the `empty`, as it were. If <exp>
907
+ * produces a value then we'll execute whatever bytecode follows this
908
+ * sequence.
909
+ */
910
+ if (!handler.first && !handler.last)
911
+ // A hack to deal with `.` as the handler; we could use a real NOOP here
912
+ handler = BLOCK(gen_op_simple(DUP), gen_op_simple(POP), handler);
913
+ exp = BLOCK(exp, gen_op_target(JUMP, handler));
914
+ return BLOCK(gen_op_target(FORK_OPT, exp), exp, handler);
915
+ }
916
+
917
+ block gen_label(const char *label, block exp) {
918
+ block cond = gen_call("_equal",
919
+ BLOCK(gen_lambda(gen_noop()),
920
+ gen_lambda(gen_op_unbound(LOADV, label))));
921
+ return gen_wildvar_binding(gen_op_simple(GENLABEL), label,
922
+ BLOCK(gen_op_simple(POP),
923
+ // try exp catch if . == $label
924
+ // then empty
925
+ // else error end
926
+ //
927
+ // Can't use gen_binop(), as that's firmly
928
+ // stuck in parser.y as it refers to things
929
+ // like EQ.
930
+ gen_try(exp,
931
+ gen_cond(cond,
932
+ gen_op_simple(BACKTRACK),
933
+ gen_call("error", gen_noop())))));
934
+ }
935
+
936
+ block gen_cbinding(const struct cfunction* cfunctions, int ncfunctions, block code) {
937
+ for (int cfunc=0; cfunc<ncfunctions; cfunc++) {
938
+ inst* i = inst_new(CLOSURE_CREATE_C);
939
+ i->imm.cfunc = &cfunctions[cfunc];
940
+ i->symbol = strdup(i->imm.cfunc->name);
941
+ code = block_bind(inst_block(i), code, OP_IS_CALL_PSEUDO);
942
+ }
943
+ return code;
944
+ }
945
+
946
+ static uint16_t nesting_level(struct bytecode* bc, inst* target) {
947
+ uint16_t level = 0;
948
+ assert(bc && target && target->compiled);
949
+ while (bc && target->compiled != bc) {
950
+ level++;
951
+ bc = bc->parent;
952
+ }
953
+ assert(bc && bc == target->compiled);
954
+ return level;
955
+ }
956
+
957
+ static int count_cfunctions(block b) {
958
+ int n = 0;
959
+ for (inst* i = b.first; i; i = i->next) {
960
+ if (i->op == CLOSURE_CREATE_C) n++;
961
+ n += count_cfunctions(i->subfn);
962
+ }
963
+ return n;
964
+ }
965
+
966
+
967
+ // Expands call instructions into a calling sequence
968
+ static int expand_call_arglist(block* b) {
969
+ int errors = 0;
970
+ block ret = gen_noop();
971
+ for (inst* curr; (curr = block_take(b));) {
972
+ if (opcode_describe(curr->op)->flags & OP_HAS_BINDING) {
973
+ if (!curr->bound_by) {
974
+ if (curr->symbol[0] == '*' && curr->symbol[1] >= '1' && curr->symbol[1] <= '3' && curr->symbol[2] == '\0')
975
+ locfile_locate(curr->locfile, curr->source, "jq: error: break used outside labeled control structure");
976
+ else
977
+ locfile_locate(curr->locfile, curr->source, "jq: error: %s/%d is not defined", curr->symbol, block_count_actuals(curr->arglist));
978
+ errors++;
979
+ // don't process this instruction if it's not well-defined
980
+ ret = BLOCK(ret, inst_block(curr));
981
+ continue;
982
+ }
983
+ }
984
+
985
+ block prelude = gen_noop();
986
+ if (curr->op == CALL_JQ) {
987
+ int actual_args = 0, desired_args = 0;
988
+ // We expand the argument list as a series of instructions
989
+ switch (curr->bound_by->op) {
990
+ default: assert(0 && "Unknown function type"); break;
991
+ case CLOSURE_CREATE:
992
+ case CLOSURE_PARAM: {
993
+ block callargs = gen_noop();
994
+ for (inst* i; (i = block_take(&curr->arglist));) {
995
+ assert(opcode_describe(i->op)->flags & OP_IS_CALL_PSEUDO);
996
+ block b = inst_block(i);
997
+ switch (i->op) {
998
+ default: assert(0 && "Unknown type of parameter"); break;
999
+ case CLOSURE_REF:
1000
+ block_append(&callargs, b);
1001
+ break;
1002
+ case CLOSURE_CREATE:
1003
+ block_append(&prelude, b);
1004
+ block_append(&callargs, gen_op_bound(CLOSURE_REF, b));
1005
+ break;
1006
+ }
1007
+ actual_args++;
1008
+ }
1009
+ curr->imm.intval = actual_args;
1010
+ curr->arglist = callargs;
1011
+
1012
+ if (curr->bound_by->op == CLOSURE_CREATE) {
1013
+ for (inst* i = curr->bound_by->arglist.first; i; i = i->next) {
1014
+ assert(i->op == CLOSURE_PARAM);
1015
+ desired_args++;
1016
+ }
1017
+ }
1018
+ break;
1019
+ }
1020
+
1021
+ case CLOSURE_CREATE_C: {
1022
+ for (inst* i; (i = block_take(&curr->arglist)); ) {
1023
+ assert(i->op == CLOSURE_CREATE); // FIXME
1024
+ block body = i->subfn;
1025
+ i->subfn = gen_noop();
1026
+ inst_free(i);
1027
+ // arguments should be pushed in reverse order, prepend them to prelude
1028
+ errors += expand_call_arglist(&body);
1029
+ prelude = BLOCK(gen_subexp(body), prelude);
1030
+ actual_args++;
1031
+ }
1032
+ assert(curr->op == CALL_JQ);
1033
+ curr->op = CALL_BUILTIN;
1034
+ curr->imm.intval = actual_args + 1 /* include the implicit input in arg count */;
1035
+ assert(curr->bound_by->op == CLOSURE_CREATE_C);
1036
+ desired_args = curr->bound_by->imm.cfunc->nargs - 1;
1037
+ assert(!curr->arglist.first);
1038
+ break;
1039
+ }
1040
+ }
1041
+
1042
+ assert(actual_args == desired_args); // because now handle this above
1043
+ }
1044
+ ret = BLOCK(ret, prelude, inst_block(curr));
1045
+ }
1046
+ *b = ret;
1047
+ return errors;
1048
+ }
1049
+
1050
+ static int compile(struct bytecode* bc, block b, struct locfile* lf) {
1051
+ int errors = 0;
1052
+ int pos = 0;
1053
+ int var_frame_idx = 0;
1054
+ bc->nsubfunctions = 0;
1055
+ errors += expand_call_arglist(&b);
1056
+ b = BLOCK(b, gen_op_simple(RET));
1057
+ jv localnames = jv_array();
1058
+ for (inst* curr = b.first; curr; curr = curr->next) {
1059
+ if (!curr->next) assert(curr == b.last);
1060
+ int length = opcode_describe(curr->op)->length;
1061
+ if (curr->op == CALL_JQ) {
1062
+ for (inst* arg = curr->arglist.first; arg; arg = arg->next) {
1063
+ length += 2;
1064
+ }
1065
+ }
1066
+ pos += length;
1067
+ curr->bytecode_pos = pos;
1068
+ curr->compiled = bc;
1069
+
1070
+ assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM);
1071
+
1072
+ if ((opcode_describe(curr->op)->flags & OP_HAS_VARIABLE) &&
1073
+ curr->bound_by == curr) {
1074
+ curr->imm.intval = var_frame_idx++;
1075
+ localnames = jv_array_append(localnames, jv_string(curr->symbol));
1076
+ }
1077
+
1078
+ if (curr->op == CLOSURE_CREATE) {
1079
+ assert(curr->bound_by == curr);
1080
+ curr->imm.intval = bc->nsubfunctions++;
1081
+ }
1082
+ if (curr->op == CLOSURE_CREATE_C) {
1083
+ assert(curr->bound_by == curr);
1084
+ int idx = bc->globals->ncfunctions++;
1085
+ bc->globals->cfunc_names = jv_array_append(bc->globals->cfunc_names,
1086
+ jv_string(curr->symbol));
1087
+ bc->globals->cfunctions[idx] = *curr->imm.cfunc;
1088
+ curr->imm.intval = idx;
1089
+ }
1090
+ }
1091
+ if (pos > 0xFFFF) {
1092
+ // too long for program counter to fit in uint16_t
1093
+ locfile_locate(lf, UNKNOWN_LOCATION,
1094
+ "function compiled to %d bytes which is too long", pos);
1095
+ errors++;
1096
+ }
1097
+ bc->codelen = pos;
1098
+ bc->debuginfo = jv_object_set(bc->debuginfo, jv_string("locals"), localnames);
1099
+ if (bc->nsubfunctions) {
1100
+ bc->subfunctions = jv_mem_alloc(sizeof(struct bytecode*) * bc->nsubfunctions);
1101
+ for (inst* curr = b.first; curr; curr = curr->next) {
1102
+ if (curr->op == CLOSURE_CREATE) {
1103
+ struct bytecode* subfn = jv_mem_alloc(sizeof(struct bytecode));
1104
+ bc->subfunctions[curr->imm.intval] = subfn;
1105
+ subfn->globals = bc->globals;
1106
+ subfn->parent = bc;
1107
+ subfn->nclosures = 0;
1108
+ subfn->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_string(curr->symbol));
1109
+ jv params = jv_array();
1110
+ for (inst* param = curr->arglist.first; param; param = param->next) {
1111
+ assert(param->op == CLOSURE_PARAM);
1112
+ assert(param->bound_by == param);
1113
+ param->imm.intval = subfn->nclosures++;
1114
+ param->compiled = subfn;
1115
+ params = jv_array_append(params, jv_string(param->symbol));
1116
+ }
1117
+ subfn->debuginfo = jv_object_set(subfn->debuginfo, jv_string("params"), params);
1118
+ errors += compile(subfn, curr->subfn, lf);
1119
+ curr->subfn = gen_noop();
1120
+ }
1121
+ }
1122
+ } else {
1123
+ bc->subfunctions = 0;
1124
+ }
1125
+ uint16_t* code = jv_mem_alloc(sizeof(uint16_t) * bc->codelen);
1126
+ bc->code = code;
1127
+ pos = 0;
1128
+ jv constant_pool = jv_array();
1129
+ int maxvar = -1;
1130
+ if (!errors) for (inst* curr = b.first; curr; curr = curr->next) {
1131
+ const struct opcode_description* op = opcode_describe(curr->op);
1132
+ if (op->length == 0)
1133
+ continue;
1134
+ code[pos++] = curr->op;
1135
+ assert(curr->op != CLOSURE_REF && curr->op != CLOSURE_PARAM);
1136
+ if (curr->op == CALL_BUILTIN) {
1137
+ assert(curr->bound_by->op == CLOSURE_CREATE_C);
1138
+ assert(!curr->arglist.first);
1139
+ code[pos++] = (uint16_t)curr->imm.intval;
1140
+ code[pos++] = curr->bound_by->imm.intval;
1141
+ } else if (curr->op == CALL_JQ) {
1142
+ assert(curr->bound_by->op == CLOSURE_CREATE ||
1143
+ curr->bound_by->op == CLOSURE_PARAM);
1144
+ code[pos++] = (uint16_t)curr->imm.intval;
1145
+ code[pos++] = nesting_level(bc, curr->bound_by);
1146
+ code[pos++] = curr->bound_by->imm.intval |
1147
+ (curr->bound_by->op == CLOSURE_CREATE ? ARG_NEWCLOSURE : 0);
1148
+ for (inst* arg = curr->arglist.first; arg; arg = arg->next) {
1149
+ assert(arg->op == CLOSURE_REF && arg->bound_by->op == CLOSURE_CREATE);
1150
+ code[pos++] = nesting_level(bc, arg->bound_by);
1151
+ code[pos++] = arg->bound_by->imm.intval | ARG_NEWCLOSURE;
1152
+ }
1153
+ } else if ((op->flags & OP_HAS_CONSTANT) && (op->flags & OP_HAS_VARIABLE)) {
1154
+ // STORE_GLOBAL: constant global, basically
1155
+ code[pos++] = jv_array_length(jv_copy(constant_pool));
1156
+ constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant));
1157
+ code[pos++] = nesting_level(bc, curr->bound_by);
1158
+ uint16_t var = (uint16_t)curr->bound_by->imm.intval;
1159
+ code[pos++] = var;
1160
+ } else if (op->flags & OP_HAS_CONSTANT) {
1161
+ code[pos++] = jv_array_length(jv_copy(constant_pool));
1162
+ constant_pool = jv_array_append(constant_pool, jv_copy(curr->imm.constant));
1163
+ } else if (op->flags & OP_HAS_VARIABLE) {
1164
+ code[pos++] = nesting_level(bc, curr->bound_by);
1165
+ uint16_t var = (uint16_t)curr->bound_by->imm.intval;
1166
+ code[pos++] = var;
1167
+ if (var > maxvar) maxvar = var;
1168
+ } else if (op->flags & OP_HAS_BRANCH) {
1169
+ assert(curr->imm.target->bytecode_pos != -1);
1170
+ assert(curr->imm.target->bytecode_pos > pos); // only forward branches
1171
+ code[pos] = curr->imm.target->bytecode_pos - (pos + 1);
1172
+ pos++;
1173
+ } else if (op->length > 1) {
1174
+ assert(0 && "codegen not implemented for this operation");
1175
+ }
1176
+ }
1177
+ bc->constants = constant_pool;
1178
+ bc->nlocals = maxvar + 2; // FIXME: frames of size zero?
1179
+ block_free(b);
1180
+ return errors;
1181
+ }
1182
+
1183
+ int block_compile(block b, struct bytecode** out, struct locfile* lf) {
1184
+ struct bytecode* bc = jv_mem_alloc(sizeof(struct bytecode));
1185
+ bc->parent = 0;
1186
+ bc->nclosures = 0;
1187
+ bc->globals = jv_mem_alloc(sizeof(struct symbol_table));
1188
+ int ncfunc = count_cfunctions(b);
1189
+ bc->globals->ncfunctions = 0;
1190
+ bc->globals->cfunctions = jv_mem_alloc(sizeof(struct cfunction) * ncfunc);
1191
+ bc->globals->cfunc_names = jv_array();
1192
+ bc->debuginfo = jv_object_set(jv_object(), jv_string("name"), jv_null());
1193
+ int nerrors = compile(bc, b, lf);
1194
+ assert(bc->globals->ncfunctions == ncfunc);
1195
+ if (nerrors > 0) {
1196
+ bytecode_free(bc);
1197
+ *out = 0;
1198
+ } else {
1199
+ *out = bc;
1200
+ }
1201
+ return nerrors;
1202
+ }
1203
+
1204
+ void block_free(block b) {
1205
+ struct inst* next;
1206
+ for (struct inst* curr = b.first; curr; curr = next) {
1207
+ next = curr->next;
1208
+ inst_free(curr);
1209
+ }
1210
+ }