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