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