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