circom/src/c_gen.js
src/c_gen.jsRaw
1const bigInt = require("big-integer");
2const utils = require("./utils");
3const assert = require("assert");
4const iterateAST = require("./iterateast");
5
6module.exports.gen = gen;
7module.exports.newRef = newRef;
8module.exports.createRefs = createRefs;
9
10function newRef(ctx, type, name, value, sizes) {
11 let label;
12 if (!name) {
13 label = ctx.getUniqueName();
14 } else {
15 label = ctx.getUniqueName(name);
16 }
17 if (Array.isArray(sizes)) {
18 // sizes = sizes;
19 } else if (utils.isDefined(value)) {
20 sizes = utils.accSizes(utils.extractSizes(value));
21 } else {
22 sizes = [1, 0];
23 }
24
25 const refId = ctx.refs.length;
26 const entry = {
27 type: type,
28 used: false,
29 sizes: sizes,
30 label: label
31 };
32 if (utils.isDefined(value)) {
33 entry.value = utils.flatArray(value);
34 }
35
36 ctx.refs.push(entry);
37 return refId;
38}
39
40function instantiateRef(ctx, refId, initValue) {
41 const v = ctx.refs[refId];
42 if (v.used) return;
43
44 if (v.type=="BIGINT") {
45 ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${v.sizes[0]});\n`;
46 ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${v.sizes[0]});\n`;
47 } else if (v.type=="INT") {
48 ctx.codeHeader += `int ${v.label};\n`;
49 } else if (v.type=="SIZES") {
50 ctx.codeHeader += `Circom_Sizes ${v.label};\n`;
51 }
52 v.used = true;
53 if (utils.isDefined(initValue)) {
54 if (v.type == "BIGINT") {
55 for (let i=0; i<initValue.length; i++) {
56 if (utils.isDefined(initValue[i])) {
57 const c = `mpz_set_str(${v.label}[${i}], "${initValue[i].toString(10)}", 10);\n`;
58 ctx.code += c;
59 }
60 }
61 }
62 }
63}
64
65function instantiateConstant(ctx, value) {
66 const sizes = utils.accSizes(utils.extractSizes(value));
67 const flatedValue = utils.flatArray(value);
68 const label = ctx.getUniqueName("_const");
69 ctx.codeHeader += `PBigInt ${label};\n`;
70 ctx.codeHeader += `${label} = ctx->allocBigInts(${sizes[0]});\n`;
71 for (let i=0; i<flatedValue.length; i++) {
72 ctx.codeHeader += `mpz_set_str(${label}[${i}], "${flatedValue[i].toString(10)}", 10);\n`;
73 }
74 ctx.codeFooter += `ctx->freeBigInts(${label}, ${sizes[0]});\n`;
75 const refId = ctx.refs.length;
76 ctx.refs.push({
77 type: "BIGINT",
78 used: true,
79 sizes: sizes,
80 label: label
81 });
82 return refId;
83}
84
85
86function createRefs(ctx, ast) {
87 const scopeLabels = [];
88 iterateAST(ast, (ast, level) => {
89 while ((scopeLabels.length>0)&&(!scopeLabels[scopeLabels.length-1].startsWith(level))) {
90 ctx.scopes.pop();
91 scopeLabels.pop();
92 }
93 if (ast.type == "DECLARE") {
94 if (ctx.scopes[ctx.scopes.length-1][ast.name.name]) return ctx.throwError(ast, `Name already defined: ${ast.name.name}`);
95 for (let i=ctx.scopes.length-2; i>=0; i--) {
96 if (ctx.scopes[i][ast.name.name]) ctx.logWarning(ast, `Shadowing variable: ${ast.name.name}`);
97 }
98 let entry = {};
99 if (ast.declareType == "COMPONENT") {
100 entry.type= "COMPONENT";
101 entry.label = ast.name.name;
102 } else if ((ast.declareType == "SIGNALIN")||
103 (ast.declareType == "SIGNALOUT")||
104 (ast.declareType == "SIGNAL")) {
105 entry.type = "SIGNAL";
106 entry.label = ast.name.name;
107 } else if (ast.declareType == "VARIABLE") {
108 entry.type = "BIGINT";
109 entry.used = false;
110 entry.sizes = null;
111 entry.label = ctx.getUniqueName(ast.name.name);
112 } else {
113 return ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
114 }
115
116 const refId = ctx.refs.length;
117 ctx.refs.push(entry);
118 ast.refId = refId;
119 ctx.scopes[ctx.scopes.length-1][ast.name.name] = refId;
120 } else if (["BLOCK", "FOR", "IF", "WHILE", "COMPUTE"].indexOf(ast.type) >= 0) {
121 scopeLabels.push(level);
122 ctx.scopes.push({});
123 } else if (ast.type == "VARIABLE") {
124 ast.refId = name2ref(ast.name);
125 }
126 });
127
128 function name2ref(n) {
129 for (let i=ctx.scopes.length-1; i>=0; i--) {
130 if (typeof ctx.scopes[i][n] !== "undefined") return ctx.scopes[i][n];
131 }
132 return -1;
133 }
134}
135
136function gen(ctx, ast) {
137 if ((ast.type == "NUMBER") ) {
138 return genNumber(ctx, ast);
139 } else if (ast.type == "VARIABLE") {
140 return genVariable(ctx, ast);
141 } else if (ast.type == "PIN") {
142 return genPin(ctx, ast);
143 } else if (ast.type == "OP") {
144 if (ast.op == "=") {
145 return genAssignement(ctx, ast);
146 } else if (ast.op == "<--") {
147 return genAssignement(ctx, ast);
148 } else if (ast.op == "<==") {
149 return genSignalAssignConstraint(ctx, ast);
150 } else if (ast.op == "===") {
151 return genConstraint(ctx, ast);
152 } else if (ast.op == "+=") {
153 return genVarAddAssignement(ctx, ast);
154 } else if (ast.op == "*=") {
155 return genVarMulAssignement(ctx, ast);
156 } else if (ast.op == "+") {
157 return genOp(ctx, ast, "add", 2);
158 } else if (ast.op == "-") {
159 return genOp(ctx, ast, "sub", 2);
160 } else if (ast.op == "UMINUS") {
161 return genOp(ctx, ast, "neg", 1);
162 } else if (ast.op == "*") {
163 return genOp(ctx, ast, "mul", 2);
164 } else if (ast.op == "%") {
165 return genOp(ctx, ast, "mod", 2);
166 } else if (ast.op == "PLUSPLUSRIGHT") {
167 return genOpOp(ctx, ast, "add", "RIGHT");
168 } else if (ast.op == "PLUSPLUSLEFT") {
169 return genOpOp(ctx, ast, "add", "LEFT");
170 } else if (ast.op == "MINUSMINUSRIGHT") {
171 return genOpOp(ctx, ast, "sub", "RIGHT");
172 } else if (ast.op == "MINUSMINUSLEFT") {
173 return genOpOp(ctx, ast, "sub", "LEFT");
174 } else if (ast.op == "**") {
175 return genOp(ctx, ast, "pow", 2);
176 } else if (ast.op == "/") {
177 return genOp(ctx, ast, "div", 2);
178 } else if (ast.op == "\\") {
179 return genOp(ctx, ast, "idiv", 2);
180 } else if (ast.op == "&") {
181 return genOp(ctx, ast, "band", 2);
182 } else if (ast.op == "|") {
183 return genOp(ctx, ast, "bor", 2);
184 } else if (ast.op == "^") {
185 return genOp(ctx, ast, "bxor", 2);
186 } else if (ast.op == "~") {
187 return genOp(ctx, ast, "bnot", 1);
188 } else if (ast.op == "&&") {
189 return genOp(ctx, ast, "land", 2);
190 } else if (ast.op == "||") {
191 return genOp(ctx, ast, "lor", 2);
192 } else if (ast.op == "!") {
193 return genOp(ctx, ast, "lnot", 1);
194 } else if (ast.op == "<<") {
195 return genOp(ctx, ast, "shl", 2);
196 } else if (ast.op == ">>") {
197 return genOp(ctx, ast, "shr", 2);
198 } else if (ast.op == "<") {
199 return genOp(ctx, ast, "lt", 2);
200 } else if (ast.op == ">") {
201 return genOp(ctx, ast, "gt", 2);
202 } else if (ast.op == "<=") {
203 return genOp(ctx, ast, "leq", 2);
204 } else if (ast.op == ">=") {
205 return genOp(ctx, ast, "geq", 2);
206 } else if (ast.op == "==") {
207 return genOp(ctx, ast, "eq", 2);
208 } else if (ast.op == "!=") {
209 return genOp(ctx, ast, "neq", 2);
210 } else if (ast.op == "?") {
211 return genTerCon(ctx, ast);
212 } else {
213 ctx.throwError(ast, "Invalid operation: " + ast.op);
214 }
215 } else if (ast.type == "DECLARE") {
216 if (ast.declareType == "COMPONENT") {
217 return genDeclareComponent(ctx, ast);
218 } else if ((ast.declareType == "SIGNALIN")||
219 (ast.declareType == "SIGNALOUT")||
220 (ast.declareType == "SIGNAL")) {
221 return genDeclareSignal(ctx, ast);
222 } else if (ast.declareType == "VARIABLE") {
223 return genDeclareVariable(ctx, ast);
224 } else {
225 ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
226 }
227 } else if (ast.type == "FUNCTIONCALL") {
228 return genFunctionCall(ctx, ast);
229 } else if (ast.type == "BLOCK") {
230 return genBlock(ctx, ast);
231 } else if (ast.type == "COMPUTE") {
232 return genCompute(ctx, ast);
233 } else if (ast.type == "FOR") {
234 return genFor(ctx, ast);
235 } else if (ast.type == "WHILE") {
236 return genWhile(ctx, ast);
237 } else if (ast.type == "IF") {
238 return genIf(ctx, ast);
239 } else if (ast.type == "RETURN") {
240 return genReturn(ctx, ast);
241 } else if (ast.type == "INCLUDE") {
242 return genInclude(ctx, ast);
243 } else if (ast.type == "ARRAY") {
244 return genArray(ctx, ast);
245 } else {
246 ctx.throwError(ast, "GEN -> Invalid AST node type: " + ast.type);
247 }
248}
249
250function genBlock(ctx, ast) {
251 ctx.scopes.push({});
252 const oldCode = ctx.code;
253 let res = null;
254 ctx.code = "";
255 for (let i=0; i<ast.statements.length; i++) {
256 if (["BLOCK", "COMPUTE", "FOR", "WHILE", "IF"].indexOf(ast.statements[i].type)<0) {
257 genSrcComment(ctx, ast.statements[i]);
258 }
259 res = gen(ctx, ast.statements[i]);
260 if (ctx.error) return;
261 }
262 ctx.code = oldCode + ctx.code;
263 ctx.scopes.pop();
264 return res;
265}
266
267function getSource(ctx, ast) {
268 let codes = [];
269 const fl= ast.first_line-1;
270 const ll = ast.last_line-1;
271 const fc = ast.first_column;
272 const lc = ast.last_column;
273 for (let i=fl; i<=ll; i++) {
274 const p1 = i==fl ? fc : 0;
275 const p2 = i==ll ? lc : -1;
276 codes.push(ctx.includedFiles[ctx.fileName][i].slice(p1, p2>=0 ? p2 : undefined));
277 }
278 return codes.join("\n");
279}
280
281function genSrcComment(ctx, ast) {
282 const code = getSource(ctx, ast);
283 ctx.code += "\n/* "+code+" */\n";
284}
285
286function genForSrcComment(ctx, ast) {
287 const init = getSource(ctx, ast.init);
288 const condition = getSource(ctx, ast.condition);
289 const step = getSource(ctx, ast.step);
290 ctx.code += `\n/* for (${init},${condition},${step}) */\n`;
291}
292
293function genIfSrcComment(ctx, ast) {
294 const condition = getSource(ctx, ast.condition);
295 ctx.code += `\n/* if (${condition}) */\n`;
296}
297
298
299function genDeclareComponent(ctx, ast) {
300 return ast.refId;
301}
302
303function genDeclareSignal(ctx, ast) {
304 return ast.refId;
305}
306
307function genDeclareVariable(ctx, ast) {
308
309
310 const v = ctx.refs[ast.refId];
311
312 let sizes;
313 if (ast.name.selectors.length>0) {
314 sizes=[];
315 for (let i=0; i< ast.name.selectors.length; i++) {
316 const sizeRef = gen(ctx, ast.name.selectors[i]);
317 const size = ctx.refs[sizeRef];
318 if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
319 if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
320 sizes.push(size.value[0].toJSNumber());
321 }
322 sizes = utils.accSizes(sizes);
323 } else {
324 sizes = null; // If not sizes, the sized are defined in the first assignement.
325 }
326
327 if ((!v.sizes)&&(sizes)) {
328 v.sizes = sizes;
329 v.value = new Array(sizes[0]);
330 }
331
332 if (v.sizes) {
333 if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a var with different sized");
334 }
335
336 return ast.refId;
337}
338
339function genNumber(ctx, ast) {
340 return newRef(ctx, "BIGINT", "_num", ast.value);
341}
342
343
344
345function genGetOffset(ctx, refOffset, vSizes, sels) {
346
347 let rN = 0;
348 let rStr = "";
349 let offset;
350
351 if (refOffset) {
352 offset = ctx.refs[refOffset];
353 if (offset.used) {
354 rStr += offset.label;
355 } else {
356 rN += offset.value.toJSNumber();
357 }
358 }
359
360 if ((sels)&&(sels.length>0)) {
361
362 let iSizes;
363 if (Array.isArray(vSizes)) {
364 iSizes = {
365 used: false,
366 sizes: vSizes
367 };
368 } else {
369 iSizes = ctx.refs[vSizes];
370 }
371
372 for (let i=0; i<sels.length; i++) {
373 const idxRef = gen(ctx, sels[i]);
374 const iIdx = ctx.refs[idxRef];
375
376 if ((!iIdx.used) && (!iSizes.used)) {
377 rN = rN + iIdx.value * iSizes.sizes[i+1];
378 } else {
379 if (rN>0) {
380 if (rStr != "") rStr += " + ";
381 rStr += rN;
382 rN =0;
383 }
384
385 if (rStr != "") rStr += " + ";
386 if (iIdx.used) {
387 rStr += iIdx.label;
388 } else {
389 rStr += iIdx.value;
390 }
391 rStr += "*";
392 if (iSizes.used) {
393 rStr += `${iSizes.label}[${i+1}]`;
394 } else {
395 rStr += iSizes.sizes[i+1];
396 }
397 }
398 }
399 }
400
401 if (rStr == "") {
402 const o = newRef(ctx, "INT", "_offset", rN);
403 return o;
404 } else {
405 if (rN>0) {
406 if (rStr != "") rStr += " + ";
407 rStr += rN;
408 rN =0;
409 }
410 if ((refOffset)&&(rStr == offset.label)) {
411 return offset.label;
412 } else {
413 const resRef = newRef(ctx, "INT", "_offset");
414 instantiateRef(ctx, resRef);
415 const res = ctx.refs[resRef];
416 ctx.code += `${res.label} = ${rStr};\n`;
417 return resRef;
418 }
419 }
420}
421
422function genVariable(ctx, ast) {
423 const v = ctx.refs[ast.refId];
424
425 const l = ast.selectors ? ast.selectors.length : 0;
426
427 if (v.type == "SIGNAL") {
428 let vOffset;
429 if (l>0) {
430 const vsOffset = genGetSigalOffset(ctx, -1, ast.name);
431 const vsSizes = genGetSignalSizes(ctx, -1, ast.name);
432 vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
433 } else {
434 vOffset = genGetSigalOffset(ctx, -1, ast.name);
435 }
436 return genGetSignal(ctx, -1, vOffset);
437
438 } else if (v.type == "BIGINT") {
439 const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
440 const offset = ctx.refs[refOffset];
441 if (v.used) {
442 if (offset.used) {
443 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
444 const res = ctx.refs[refRes];
445 res.used = true;
446 ctx.codeHeader += `PBigInt ${res.label};\n`;
447 ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`;
448 return refRes;
449 } else if ((offset.value[0])||(l>0)) {
450 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
451 const res = ctx.refs[refRes];
452 res.used = true;
453 ctx.codeHeader += `PBigInt ${res.label};\n`;
454 ctx.code += `${res.label} = ${v.label} + ${offset.value[0]};\n`;
455 return refRes;
456 } else {
457 return ast.refId;
458 }
459 } else {
460 if (offset.used) {
461 instantiateRef(ctx, ast.refId, v.value);
462 const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
463 const res = ctx.refs[resRef];
464 res.used = true;
465 ctx.codeHeader += `PBigInt ${res};\n`;
466 ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`;
467 return res;
468 } else {
469 // return newSubRef(ctx, ast.name, ast.selectors);
470 return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l));
471 }
472 }
473 }
474}
475
476
477function genPin(ctx, ast) {
478 let vcIdx;
479 if (ast.component.selectors.length>0) {
480 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.component.name);
481 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.component.name);
482 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors );
483 } else {
484 vcIdx = genGetSubComponentOffset(ctx, -1, ast.component.name);
485 }
486
487 let vsIdx;
488 if (ast.pin.selectors.length>0) {
489 const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
490 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name);
491 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors );
492 } else {
493 vsIdx = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
494 }
495
496 return genGetSignal(ctx, vcIdx, vsIdx);
497}
498
499function genGetSubComponentOffset(ctx, cIdxRef, label) {
500 const refOffset = newRef(ctx, "INT", "_compIdx");
501 const offset = ctx.refs[refOffset];
502 instantiateRef(ctx, refOffset);
503
504 const h = utils.fnvHash(label);
505 let s;
506 if (cIdxRef>=0) {
507 const cIdx = ctx.refs[cIdxRef];
508 s = cIdx.label;
509 } else {
510 s = "ctx->cIdx";
511 }
512 ctx.code += `${offset.label} = ctx->getSubComponentOffset(${s}, 0x${h}LL /* ${label} */);\n`;
513 return refOffset;
514}
515
516function genGetSubComponentSizes(ctx, cIdxRef, label) {
517 const sizesRef = newRef(ctx, "SIZES", "_compSizes");
518 const sizes = ctx.refs[sizesRef];
519 instantiateRef(ctx, sizesRef);
520
521 const h = utils.fnvHash(label);
522 let s;
523 if (cIdxRef>=0) {
524 const cIdx = ctx.refs[cIdxRef];
525 s = cIdx.label;
526 } else {
527 s = "ctx->cIdx";
528 }
529 ctx.code += `${sizes.label} = ctx->getSubComponentSizes(${s}, 0x${h}LL /* ${label} */);\n`;
530 return sizesRef;
531}
532
533function genGetSigalOffset(ctx, cIdxRef, label) {
534 const refOffset = newRef(ctx, "INT", "_sigIdx");
535 const offset = ctx.refs[refOffset];
536 instantiateRef(ctx, refOffset);
537
538 const h = utils.fnvHash(label);
539 let s;
540 if (cIdxRef>=0) {
541 const cIdx = ctx.refs[cIdxRef];
542 s = cIdx.label;
543 } else {
544 s = "ctx->cIdx";
545 }
546 ctx.code += `${offset.label} = ctx->getSignalOffset(${s}, 0x${h}LL /* ${label} */);\n`;
547 return refOffset;
548}
549
550function genGetSignalSizes(ctx, cIdxRef, label) {
551 const sizesRef = newRef(ctx, "SIZES", "_sigSizes");
552 const sizes = ctx.refs[sizesRef];
553 instantiateRef(ctx, sizesRef);
554
555 let s;
556 if (cIdxRef>=0) {
557 const cIdx = ctx.refs[cIdxRef];
558 s = cIdx.label;
559 } else {
560 s = "ctx->cIdx";
561 }
562 const h = utils.fnvHash(label);
563 ctx.code += `${sizes.label} = ctx->getSignalSizes(${s}, 0x${h}LL /* ${label} */);\n`;
564 return sizesRef;
565}
566
567function genSetSignal(ctx, cIdxRef, sIdxRef, valueRef) {
568 const v = ctx.refs[valueRef];
569 if (!v.used) {
570 instantiateRef(ctx, valueRef, v.value);
571 }
572 let s;
573 if (cIdxRef>=0) {
574 const cIdx = ctx.refs[cIdxRef];
575 s = cIdx.label;
576 } else {
577 s = "ctx->cIdx";
578 }
579 const sIdx = ctx.refs[sIdxRef];
580 ctx.code += `ctx->setSignal(${s}, ${sIdx.label}, ${v.label});\n`;
581
582 return valueRef;
583}
584
585function genGetSignal(ctx, cIdxRef, sIdxRef) {
586 const resRef = newRef(ctx, "BIGINT", "_sigValue");
587 const res = ctx.refs[resRef];
588 instantiateRef(ctx, resRef);
589 let s;
590 if (cIdxRef>=0) {
591 const cIdx = ctx.refs[cIdxRef];
592 s = cIdx.label;
593 } else {
594 s = "ctx->cIdx";
595 }
596 const sIdx = ctx.refs[sIdxRef];
597 ctx.code += `ctx->getSignal(${s}, ${sIdx.label}, ${res.label});\n`;
598 return resRef;
599}
600
601function genPinAssignement(ctx, ast) {
602 let vcIdx;
603 if (ast.values[0].component.selectors.length>0) {
604 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
605 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.values[0].component.name);
606 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors );
607 } else {
608 vcIdx = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
609 }
610
611 let vsIdx;
612 if (ast.values[0].pin.selectors.length>0) {
613 const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
614 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name);
615 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors );
616 } else {
617 vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
618 }
619
620 const vVal = gen(ctx, ast.values[1]);
621
622 genSetSignal(ctx, vcIdx, vsIdx, vVal);
623
624 return vVal;
625}
626
627function genSignalAssignmen(ctx, ast, lName, sels, rName) {
628 let vsIdx;
629 const signal = ctx.refs[lName];
630 if (sels.length>0) {
631 const vsOffset = genGetSigalOffset(ctx, -1, signal.label);
632 const vsSizes = genGetSignalSizes(ctx, -1, signal.label);
633 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels );
634 } else {
635 vsIdx = genGetSigalOffset(ctx, -1, signal.label);
636 }
637
638 return genSetSignal(ctx, -1, vsIdx, rName);
639}
640
641function genVarAssignment(ctx, ast, lRef, sels, rRef) {
642
643 const left = ctx.refs[lRef];
644 const right = ctx.refs[rRef];
645 if (!utils.isDefined(left.sizes)) {
646 left.sizes = right.sizes;
647 left.value = new Array(left.sizes[0]);
648 }
649 if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return ctx.throwError(ast, "Sizes do not match");
650
651 const oRef = genGetOffset(ctx, 0, left.sizes, sels);
652 const offset = ctx.refs[oRef];
653
654 let instantiated=false;
655 if (left.used) {
656 instantiateRef(ctx, rRef, right.value);
657 instantiated=true;
658 } else if (right.used) {
659 if (sels.length == 0) {
660 instantiateRef(ctx,lRef);
661 } else {
662 instantiateRef(ctx,lRef, left.value);
663 }
664 instantiated=true;
665 } else if (offset.used) {
666 instantiateRef(ctx, rRef, right.value);
667 if (sels.length == 0) {
668 instantiateRef(ctx,lRef);
669 } else {
670 instantiateRef(ctx,lRef, left.value);
671 }
672 instantiated=true;
673 }
674
675 if (instantiated) {
676 if (offset.used) {
677 ctx.code += `ctx->field->copyn(${left.label} + ${offset.label}, ${right.label}, ${right.sizes[0]});\n`;
678 } else {
679 if (offset.value[0]>0) {
680 ctx.code += `ctx->field->copyn(${left.label} + ${offset.value[0]}, ${right.label}, ${right.sizes[0]});\n`;
681 } else {
682 ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`;
683 }
684 }
685 } else {
686 if (offset.value[0]>0) {
687 for (let i=0; i<right.sizes[0]; i++) left.value[offset.value[0] + i] = right.value[i];
688 } else {
689 for (let i=0; i<right.sizes[0]; i++) left.value[i] = right.value[i];
690 }
691 }
692}
693
694function genAssignement(ctx, ast) {
695
696 let lRef;
697 let sels;
698
699 if (ctx.error) return;
700
701 if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast);
702
703 if (ast.values[0].type == "DECLARE") {
704 lRef = gen(ctx, ast.values[0]);
705 if (ctx.error) return;
706 sels = [];
707 } else {
708 lRef = ast.values[0].refId;
709 sels = ast.values[0].selectors;
710 }
711
712
713 const left = ctx.refs[lRef];
714 if (!left) return ctx.throwError(ast, "Variable does not exists: "+ast.values[0].name);
715
716 // Component instantiation is already done.
717 if (left.type == "COMPONENT") return;
718
719 const rRef = gen(ctx, ast.values[1]);
720 if (ctx.error) return;
721
722 if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lRef, sels, rRef);
723
724 if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lRef, sels, rRef);
725
726 return ctx.throwError(ast, "Assigning to invalid");
727}
728
729function genConstraint(ctx, ast) {
730 const aRef = gen(ctx, ast.values[0]);
731 const a = ctx.refs[aRef];
732 if (ctx.error) return;
733 const bRef = gen(ctx, ast.values[1]);
734 const b = ctx.refs[bRef];
735 if (ctx.error) return;
736 const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
737 ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`;
738}
739
740
741function genArray(ctx, ast) {
742 let subSizes;
743 let instantiate = false;
744 if (ast.values.length == 0) return ctx.throwError(ast, "Arrays with zero elements not allowed");
745 const value = [];
746 const refs = [];
747 for (let i=0; i<ast.values.length; i++) {
748 const eRef = gen(ctx, ast.values[i]);
749 const e = ctx.refs[eRef];
750
751 if (i==0) {
752 subSizes = e.sizes;
753 } else {
754 if (!utils.sameSizes(subSizes, e.sizes)) return ctx.throwError(ast, "Heteroeneus array not allowed");
755 }
756 if (e.used) {
757 instantiate = true;
758 }
759 if (!instantiate) {
760 value.push(...e.value);
761 }
762 refs.push(eRef);
763 }
764
765 const newSize = [subSizes[0]*ast.values.length , ...subSizes];
766
767 if (instantiate) {
768 const rRef = newRef(ctx, "BIGINT", "_arr", null, newSize);
769 instantiateRef(ctx, rRef);
770 for (let i=0; i<ast.values.length; i++) {
771 const v = ctx.refs[refs[i]];
772 const r = ctx.refs[rRef];
773 ctx.code += `ctx->field->copyn(${r.label}+${i*subSizes[0]}, ${v.label}, ${subSizes[0]});\n`;
774 }
775 return rRef;
776 } else {
777 const rRef = newRef(ctx, "BIGINT", "_arr", value, newSize);
778 return rRef;
779 }
780
781}
782
783
784function genFunctionCall(ctx, ast) {
785 const params = [];
786 for (let i=0; i<ast.params.length; i++) {
787 const pRef = gen(ctx, ast.params[i]);
788 params.push(ctx.refs[pRef]);
789 }
790
791 const fn = ctx.buildFunction(ast.name, params);
792 if (ctx.error) return;
793
794 if (fn.type == "VARVAL_CONSTSIZE") {
795 const resRef = newRef(ctx, "BIGINT", `_ret${ast.name}Sizes`, null, fn.returnSizes);
796 const res = ctx.refs[resRef];
797 instantiateRef(ctx, resRef);
798
799 ctx.code +=`${fn.fnName}(ctx, ${res.label}`;
800 for (let i=0; i<params.length; i++) {
801 if (params[i].used) ctx.code+=`,${params[i].label}`;
802 }
803 ctx.code+=");\n";
804
805 return resRef;
806 } else {
807 const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes);
808 return res;
809 }
810}
811
812function enterConditionalCode(ctx, ast) {
813 if (!ctx.conditionalCode) {
814 iterateAST(ast, (ast) => {
815 if (ast.type == "OP") {
816 if (["=", "+=", "*=", "PLUSPLUSLEFT", "PLUSPLUSRIGHT", "MINUSMINUSLEFT", "MINUSMINUSRIGHT"].indexOf(ast.op) >= 0) {
817 let refId;
818 refId = ast.values[0].refId;
819 const ref = ctx.refs[refId];
820 instantiateRef(ctx, refId, ref.value);
821 }
822 }
823 });
824 ctx.conditionalCode = 1;
825 } else {
826 ctx.conditionalCode ++;
827 }
828}
829
830function leaveConditionalCode(ctx) {
831 assert(ctx.conditionalCode, "Leaving conditional code too many times");
832 ctx.conditionalCode --;
833 if (!ctx.conditionalCode) {
834 delete ctx.conditionalCode;
835 }
836}
837
838function genFor(ctx, ast) {
839 genForSrcComment(ctx, ast);
840 let inLoop = false;
841 ctx.scopes.push({});
842 gen(ctx, ast.init);
843 if (ctx.error) return;
844
845 let end=false;
846 let condVarRef;
847 let condVar;
848
849
850 const condRef = gen(ctx, ast.condition);
851 if (ctx.error) return;
852
853 const cond = ctx.refs[condRef];
854 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
855
856 if (cond.used) {
857 inLoop = true;
858 enterConditionalCode(ctx, ast);
859 condVarRef = newRef(ctx, "INT", "_cond");
860 condVar = ctx.refs[condVarRef];
861 instantiateRef(ctx, condVarRef);
862
863 ctx.code +=
864 `${condVar.label} = ctx->field->isTrue(${cond.label});\n` +
865 `while (${condVar.label}) {\n`;
866 } else {
867 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
868 if (cond.value[0].isZero()) end=true;
869 }
870
871
872 while (!end) {
873
874 const oldCode = ctx.code;
875 ctx.code = "";
876
877 if (ast.body.type != "BLOCK") genSrcComment(ctx, ast.body);
878 gen(ctx, ast.body);
879 if (ctx.error) return;
880
881 gen(ctx, ast.step);
882 if (ctx.error) return;
883
884 const condRef2 = gen(ctx, ast.condition);
885 if (ctx.error) return;
886
887 const cond2 = ctx.refs[condRef2];
888
889 if (!inLoop) {
890 if (cond2.used) {
891 ctx.code = oldCode + ctx.code;
892 inLoop = true;
893 enterConditionalCode(ctx, ast);
894 condVar = newRef(ctx, "INT", "_cond");
895 instantiateRef(ctx, condVar);
896
897 ctx.code =
898 oldCode +
899 ctx.code +
900 `${condVar.label} = ctx->field->isTrue(${cond2.label});\n` +
901 `while (${condVar.label}) {\n`;
902 } else {
903 ctx.code = oldCode + ctx.code;
904 if (cond2.value[0].isZero()) end=true;
905 }
906 } else {
907 ctx.code =
908 oldCode +
909 utils.ident(
910 ctx.code +
911 `${condVar.label} = ctx->field->isTrue(${cond2.label});\n`);
912 end=true;
913 }
914 }
915 if (inLoop) {
916 ctx.code += "}\n";
917 leaveConditionalCode(ctx);
918 }
919 ctx.scopes.pop();
920}
921
922function genWhile(ctx, ast) {
923 const condition = gen(ctx, ast.condition);
924 if (ctx.error) return;
925 const body = gen(ctx, ast.body);
926 if (ctx.error) return;
927 return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`;
928}
929
930function genCompute(ctx, ast) {
931 const body = gen(ctx, ast.body);
932 if (ctx.error) return;
933 return `{\n${body}\n}\n`;
934}
935
936function genIf(ctx, ast) {
937 genIfSrcComment(ctx, ast);
938 const condRef = gen(ctx, ast.condition);
939 if (ctx.error) return;
940 const cond = ctx.refs[condRef];
941 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
942
943 if (cond.used) {
944 enterConditionalCode(ctx, ast);
945
946 ctx.code += `if (ctx->field->isTrue(${cond.label})) {\n`;
947
948 const oldCode = ctx.code;
949 ctx.code = "";
950
951 gen(ctx, ast.then);
952 if (ctx.error) return;
953
954 ctx.code = oldCode + utils.ident(ctx.code);
955
956 if (ast.else) {
957 ctx.code += "} else {\n";
958 const oldCode = ctx.code;
959 ctx.code = "";
960 gen(ctx, ast.else);
961 if (ctx.error) return;
962 ctx.code = oldCode + utils.ident(ctx.code);
963 }
964
965 ctx.code += "}\n";
966
967 } else {
968 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
969 if (!cond.value[0].isZero()) {
970 gen(ctx, ast.then);
971 } else {
972 if (ast.else) {
973 gen(ctx, ast.else);
974 }
975 }
976 }
977}
978
979
980function genReturn(ctx, ast) {
981 const vRef = gen(ctx, ast.value);
982 const v= ctx.refs[vRef];
983 if (ctx.returnSizes) {
984 if (!utils.sizesEqual(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
985 } else {
986 ctx.returnSizes = v.sizes;
987 }
988 if (ctx.conditionalCode) {
989 instantiateRef(ctx, vRef, v.value);
990 }
991 if (v.used) {
992 ctx.code += `ctx->field->copyn(__retValue, ${v.label}, ${v.sizes[0]});\n`;
993 } else {
994 if (!utils.isDefined(v.value)) return ctx.throwError(ast, "Returning an unknown value");
995 if (!utils.isDefined(ctx.returnValue)) {
996 ctx.returnValue = v.value;
997 }
998 }
999 ctx.code += "goto returnFunc;\n";
1000 return vRef;
1001}
1002
1003
1004
1005function genSignalAssignConstraint(ctx, ast) {
1006 const res = genAssignement(ctx, ast);
1007 // genConstraint(ctx, ast);
1008 return res;
1009 // return genVarAssignement(ctx, ast);
1010}
1011
1012function genVarAddAssignement(ctx, ast) {
1013 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
1014}
1015
1016function genVarMulAssignement(ctx, ast) {
1017 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
1018}
1019
1020function genOpOp(ctx, ast, op, lr) {
1021
1022 if (ast.values[0].type != "VARIABLE") return ctx.throwError(ast, "incrementing a non variable");
1023
1024 const vRef = ast.values[0].refId;
1025
1026 const vevalRef = gen(ctx, ast.values[0]);
1027 if (ctx.error) return;
1028 const veval = ctx.refs[vevalRef];
1029
1030 if (veval.type != "BIGINT") return ctx.throwError(ast, "incrementing a non variable");
1031
1032 const resRef = newRef(ctx, "BIGINT", "_tmp");
1033 const res = ctx.refs[resRef];
1034 if (veval.used) {
1035 instantiateRef(ctx, resRef);
1036 ctx.code += `ctx->field->${op}(${res.label}, ${veval.label}, &(ctx->field->one));\n`;
1037 } else {
1038 res.value = [ctx.field[op](veval.value[0], bigInt(1))];
1039 }
1040 genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
1041 if (lr == "RIGHT") {
1042 return vevalRef;
1043 } else if (lr == "LEFT") {
1044 return resRef;
1045 }
1046}
1047
1048function genOp(ctx, ast, op, nOps) {
1049 const vals = [];
1050 const valRefs = [];
1051
1052 var anyUsed=false;
1053
1054 for (let i=0; i<nOps; i++) {
1055 const ref = gen(ctx, ast.values[i]);
1056 if (ctx.error) return;
1057 let v = ctx.refs[ref];
1058 valRefs.push(ref);
1059 vals.push(v);
1060
1061 if (!utils.sameSizes(v.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
1062 if ( (!v.used)
1063 &&( (!utils.isDefined(v.value))
1064 ||(!utils.isDefined(v.value[0]))))
1065 return ctx.throwError(ast, "Using a not assigned varialble: ");
1066
1067 if (v.used) anyUsed=true;
1068 }
1069
1070 let rRef;
1071 if (anyUsed) {
1072 for (let i=0; i<nOps; i++) {
1073 if (!vals[i].used) {
1074 valRefs[i] = instantiateConstant(ctx, vals[i].value);
1075 vals[i] = ctx.refs[valRefs[i]];
1076 }
1077 }
1078
1079 rRef = newRef(ctx, "BIGINT", "_tmp");
1080 instantiateRef(ctx, rRef);
1081 const r = ctx.refs[rRef];
1082 let c = `ctx->field->${op}(${r.label}`;
1083 for (let i=0; i<nOps; i++) {
1084 c+=`,${vals[i].label}`;
1085 }
1086 c += ");\n";
1087 ctx.code += c;
1088 } else {
1089 const params = [];
1090 for (let i=0; i<nOps; i++) {
1091 params.push(vals[i].value[0]);
1092 }
1093 rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](...params));
1094 }
1095 return rRef;
1096}
1097
1098function genBAnd(ctx, ast) {
1099 const a = gen(ctx, ast.values[0]);
1100 if (ctx.error) return;
1101 const b = gen(ctx, ast.values[1]);
1102 if (ctx.error) return;
1103 return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
1104}
1105
1106function genAnd(ctx, ast) {
1107 const a = gen(ctx, ast.values[0]);
1108 if (ctx.error) return;
1109 const b = gen(ctx, ast.values[1]);
1110 if (ctx.error) return;
1111 return `((bigInt(${a}).neq(bigInt(0)) && bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
1112}
1113
1114function genOr(ctx, ast) {
1115 const a = gen(ctx, ast.values[0]);
1116 if (ctx.error) return;
1117 const b = gen(ctx, ast.values[1]);
1118 if (ctx.error) return;
1119 return `((bigInt(${a}).neq(bigInt(0)) || bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
1120}
1121
1122function genShl(ctx, ast) {
1123 const a = gen(ctx, ast.values[0]);
1124 if (ctx.error) return;
1125 const b = gen(ctx, ast.values[1]);
1126 if (ctx.error) return;
1127 return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shl(bigInt(${b})).and(__MASK__)`;
1128}
1129
1130function genShr(ctx, ast) {
1131 const a = gen(ctx, ast.values[0]);
1132 if (ctx.error) return;
1133 const b = gen(ctx, ast.values[1]);
1134 if (ctx.error) return;
1135 return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`;
1136}
1137
1138function genTerCon(ctx, ast) {
1139 const a = gen(ctx, ast.values[0]);
1140 if (ctx.error) return;
1141 const b = gen(ctx, ast.values[1]);
1142 if (ctx.error) return;
1143 const c = gen(ctx, ast.values[2]);
1144 if (ctx.error) return;
1145 return `bigInt(${a}).neq(bigInt(0)) ? (${b}) : (${c})`;
1146}
1147
1148function genInclude(ctx, ast) {
1149 return ast.block ? gen(ctx, ast.block) : "";
1150}
1151
1152