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