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