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 genBinaryOp(ctx, ast, "sub");
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 genBinaryOp(ctx, ast, "mod");
166 } else if (ast.op == "PLUSPLUSRIGHT") {
167 return genOpOp(ctx, ast, "add", "RIGHT");
168 } else if (ast.op == "PLUSPLUSLEFT") {
169 return genOpOp(ctx, ast, "add", "LEFT");
170 } else if (ast.op == "MINUSMINUSRIGHT") {
171 return genOpOp(ctx, ast, "sub", "RIGHT");
172 } else if (ast.op == "MINUSMINUSLEFT") {
173 return genOpOp(ctx, ast, "sub", "LEFT");
174 } else if (ast.op == "**") {
175 return genExp(ctx, ast);
176 } else if (ast.op == "/") {
177 return genBinaryOp(ctx, ast, "div");
178 } else if (ast.op == "\\") {
179 return genBinaryOp(ctx, ast, "idiv");
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 genBinaryOp(ctx, ast, "gt");
194 } else if (ast.op == "<=") {
195 return genBinaryOp(ctx, ast, "leq");
196 } else if (ast.op == ">=") {
197 return genBinaryOp(ctx, ast, "geq");
198 } else if (ast.op == "==") {
199 return genBinaryOp(ctx, ast, "eq");
200 } else if (ast.op == "!=") {
201 return genBinaryOp(ctx, ast, "neq");
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
285function genIfSrcComment(ctx, ast) {
286 const condition = getSource(ctx, ast.condition);
287 ctx.code += `\n/* if (${condition}) */\n`;
288}
289
290
291function genDeclareComponent(ctx, ast) {
292 return ast.refId;
293}
294
295function genDeclareSignal(ctx, ast) {
296 return ast.refId;
297}
298
299function genDeclareVariable(ctx, ast) {
300
301
302 const v = ctx.refs[ast.refId];
303
304 let sizes;
305 if (ast.name.selectors.length>0) {
306 sizes=[];
307 for (let i=0; i< ast.name.selectors.length; i++) {
308 const sizeRef = gen(ctx, ast.name.selectors[i]);
309 const size = ctx.refs[sizeRef];
310 if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
311 if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
312 sizes.push(size.value[0].toJSNumber());
313 }
314 sizes = utils.accSizes(sizes);
315 } else {
316 sizes = null; // If not sizes, the sized are defined in the first assignement.
317 }
318
319 if ((!v.sizes)&&(sizes)) {
320 v.sizes = sizes;
321 v.value = new Array(sizes[0]);
322 }
323
324 if (v.sizes) {
325 if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a var with different sized");
326 }
327
328 return ast.refId;
329}
330
331function genNumber(ctx, ast) {
332 return newRef(ctx, "BIGINT", "_num", ast.value);
333}
334
335
336
337function genGetOffset(ctx, refOffset, vSizes, sels) {
338
339 let rN = 0;
340 let rStr = "";
341 let offset;
342
343 if (refOffset) {
344 offset = ctx.refs[refOffset];
345 if (offset.used) {
346 rStr += offset.label;
347 } else {
348 rN += offset.value.toJSNumber();
349 }
350 }
351
352 if ((sels)&&(sels.length>0)) {
353
354 let iSizes;
355 if (Array.isArray(vSizes)) {
356 iSizes = {
357 used: false,
358 sizes: vSizes
359 };
360 } else {
361 iSizes = ctx.refs[vSizes];
362 }
363
364 for (let i=0; i<sels.length; i++) {
365 const idxRef = gen(ctx, sels[i]);
366 const iIdx = ctx.refs[idxRef];
367
368 if ((!iIdx.used) && (!iSizes.used)) {
369 rN = rN + iIdx.value * iSizes.sizes[i+1];
370 } else {
371 if (rN>0) {
372 if (rStr != "") rStr += " + ";
373 rStr += rN;
374 rN =0;
375 }
376
377 if (rStr != "") rStr += " + ";
378 if (iIdx.used) {
379 rStr += iIdx.label;
380 } else {
381 rStr += iIdx.value;
382 }
383 rStr += "*";
384 if (iSizes.used) {
385 rStr += `${iSizes.label}[${i+1}]`;
386 } else {
387 rStr += iSizes.sizes[i+1];
388 }
389 }
390 }
391 }
392
393 if (rStr == "") {
394 const o = newRef(ctx, "INT", "_offset", rN);
395 return o;
396 } else {
397 if (rN>0) {
398 if (rStr != "") rStr += " + ";
399 rStr += rN;
400 rN =0;
401 }
402 if ((refOffset)&&(rStr == offset.label)) {
403 return offset.label;
404 } else {
405 const resRef = newRef(ctx, "INT", "_offset");
406 instantiateRef(ctx, resRef);
407 const res = ctx.refs[resRef];
408 ctx.code += `${res.label} = ${rStr};\n`;
409 return resRef;
410 }
411 }
412}
413
414function genVariable(ctx, ast) {
415 const v = ctx.refs[ast.refId];
416
417 const l = ast.selectors ? ast.selectors.length : 0;
418
419 if (v.type == "SIGNAL") {
420 let vOffset;
421 if (l>0) {
422 const vsOffset = genGetSigalOffset(ctx, -1, ast.name);
423 const vsSizes = genGetSignalSizes(ctx, -1, ast.name);
424 vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
425 } else {
426 vOffset = genGetSigalOffset(ctx, -1, ast.name);
427 }
428 return genGetSignal(ctx, -1, vOffset);
429
430 } else if (v.type == "BIGINT") {
431 const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
432 const offset = ctx.refs[refOffset];
433 if (v.used) {
434 if (offset.used) {
435 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
436 const res = ctx.refs[refRes];
437 res.used = true;
438 ctx.codeHeader += `PBigInt ${res.label};\n`;
439 ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`;
440 return refRes;
441 } else if ((offset.value[0])||(l>0)) {
442 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
443 const res = ctx.refs[refRes];
444 res.used = true;
445 ctx.codeHeader += `PBigInt ${res.label};\n`;
446 ctx.code += `${res.label} = ${v.label} + ${offset.value[0]};\n`;
447 return refRes;
448 } else {
449 return ast.refId;
450 }
451 } else {
452 if (offset.used) {
453 instantiateRef(ctx, ast.refId, v.value);
454 const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
455 const res = ctx.refs[resRef];
456 res.used = true;
457 ctx.codeHeader += `PBigInt ${res};\n`;
458 ctx.code += `${res.label} = ${v.label} + ${offset.label};\n`;
459 return res;
460 } else {
461 // return newSubRef(ctx, ast.name, ast.selectors);
462 return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l));
463 }
464 }
465 }
466}
467
468
469function genPin(ctx, ast) {
470 let vcIdx;
471 if (ast.component.selectors.length>0) {
472 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.component.name);
473 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.component.name);
474 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors );
475 } else {
476 vcIdx = genGetSubComponentOffset(ctx, -1, ast.component.name);
477 }
478
479 let vsIdx;
480 if (ast.pin.selectors.length>0) {
481 const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
482 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name);
483 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors );
484 } else {
485 vsIdx = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
486 }
487
488 return genGetSignal(ctx, vcIdx, vsIdx);
489}
490
491function genGetSubComponentOffset(ctx, cIdxRef, label) {
492 const refOffset = newRef(ctx, "INT", "_compIdx");
493 const offset = ctx.refs[refOffset];
494 instantiateRef(ctx, refOffset);
495
496 const h = utils.fnvHash(label);
497 let s;
498 if (cIdxRef>=0) {
499 const cIdx = ctx.refs[cIdxRef];
500 s = cIdx.label;
501 } else {
502 s = "ctx->cIdx";
503 }
504 ctx.code += `${offset.label} = ctx->getSubComponentOffset(${s}, 0x${h}LL /* ${label} */);\n`;
505 return refOffset;
506}
507
508function genGetSubComponentSizes(ctx, cIdxRef, label) {
509 const sizesRef = newRef(ctx, "SIZES", "_compSizes");
510 const sizes = ctx.refs[sizesRef];
511 instantiateRef(ctx, sizesRef);
512
513 const h = utils.fnvHash(label);
514 let s;
515 if (cIdxRef>=0) {
516 const cIdx = ctx.refs[cIdxRef];
517 s = cIdx.label;
518 } else {
519 s = "ctx->cIdx";
520 }
521 ctx.code += `${sizes.label} = ctx->getSubComponentSizes(${s}, 0x${h}LL /* ${label} */);\n`;
522 return sizesRef;
523}
524
525function genGetSigalOffset(ctx, cIdxRef, label) {
526 const refOffset = newRef(ctx, "INT", "_sigIdx");
527 const offset = ctx.refs[refOffset];
528 instantiateRef(ctx, refOffset);
529
530 const h = utils.fnvHash(label);
531 let s;
532 if (cIdxRef>=0) {
533 const cIdx = ctx.refs[cIdxRef];
534 s = cIdx.label;
535 } else {
536 s = "ctx->cIdx";
537 }
538 ctx.code += `${offset.label} = ctx->getSignalOffset(${s}, 0x${h}LL /* ${label} */);\n`;
539 return refOffset;
540}
541
542function genGetSignalSizes(ctx, cIdxRef, label) {
543 const sizesRef = newRef(ctx, "SIZES", "_sigSizes");
544 const sizes = ctx.refs[sizesRef];
545 instantiateRef(ctx, sizesRef);
546
547 let s;
548 if (cIdxRef>=0) {
549 const cIdx = ctx.refs[cIdxRef];
550 s = cIdx.label;
551 } else {
552 s = "ctx->cIdx";
553 }
554 const h = utils.fnvHash(label);
555 ctx.code += `${sizes.label} = ctx->getSignalSizes(${s}, 0x${h}LL /* ${label} */);\n`;
556 return sizesRef;
557}
558
559function genSetSignal(ctx, cIdxRef, sIdxRef, valueRef) {
560 const v = ctx.refs[valueRef];
561 if (!v.used) {
562 instantiateRef(ctx, valueRef, v.value);
563 }
564 let s;
565 if (cIdxRef>=0) {
566 const cIdx = ctx.refs[cIdxRef];
567 s = cIdx.label;
568 } else {
569 s = "ctx->cIdx";
570 }
571 const sIdx = ctx.refs[sIdxRef];
572 ctx.code += `ctx->setSignal(${s}, ${sIdx.label}, ${v.label});\n`;
573
574 return valueRef;
575}
576
577function genGetSignal(ctx, cIdxRef, sIdxRef) {
578 const resRef = newRef(ctx, "BIGINT", "_sigValue");
579 const res = ctx.refs[resRef];
580 instantiateRef(ctx, resRef);
581 let s;
582 if (cIdxRef>=0) {
583 const cIdx = ctx.refs[cIdxRef];
584 s = cIdx.label;
585 } else {
586 s = "ctx->cIdx";
587 }
588 const sIdx = ctx.refs[sIdxRef];
589 ctx.code += `ctx->getSignal(${s}, ${sIdx.label}, ${res.label});\n`;
590 return resRef;
591}
592
593function genPinAssignement(ctx, ast) {
594 let vcIdx;
595 if (ast.values[0].component.selectors.length>0) {
596 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
597 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.values[0].component.name);
598 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors );
599 } else {
600 vcIdx = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
601 }
602
603 let vsIdx;
604 if (ast.values[0].pin.selectors.length>0) {
605 const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
606 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name);
607 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors );
608 } else {
609 vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
610 }
611
612 const vVal = gen(ctx, ast.values[1]);
613
614 genSetSignal(ctx, vcIdx, vsIdx, vVal);
615
616 return vVal;
617}
618
619function genSignalAssignmen(ctx, ast, lName, sels, rName) {
620 let vsIdx;
621 const signal = ctx.refs[lName];
622 if (sels.length>0) {
623 const vsOffset = genGetSigalOffset(ctx, -1, signal.label);
624 const vsSizes = genGetSignalSizes(ctx, -1, signal.label);
625 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels );
626 } else {
627 vsIdx = genGetSigalOffset(ctx, -1, signal.label);
628 }
629
630 return genSetSignal(ctx, -1, vsIdx, rName);
631}
632
633function genVarAssignment(ctx, ast, lRef, sels, rRef) {
634
635 const left = ctx.refs[lRef];
636 const right = ctx.refs[rRef];
637 if (!utils.isDefined(left.sizes)) {
638 left.sizes = right.sizes;
639 left.value = new Array(left.sizes[0]);
640 }
641 if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return ctx.throwError(ast, "Sizes do not match");
642
643 const oRef = genGetOffset(ctx, 0, left.sizes, sels);
644 const offset = ctx.refs[oRef];
645
646 let instantiated=false;
647 if (left.used) {
648 instantiateRef(ctx, rRef, right.value);
649 instantiated=true;
650 } else if (right.used) {
651 if (sels.length == 0) {
652 instantiateRef(ctx,lRef);
653 } else {
654 instantiateRef(ctx,lRef, left.value);
655 }
656 instantiated=true;
657 } else if (offset.used) {
658 instantiateRef(ctx, rRef, right.value);
659 if (sels.length == 0) {
660 instantiateRef(ctx,lRef);
661 } else {
662 instantiateRef(ctx,lRef, left.value);
663 }
664 instantiated=true;
665 }
666
667 if (instantiated) {
668 if (offset.used) {
669 ctx.code += `ctx->field->copyn(${left.label} + ${offset.label}, ${right.label}, ${right.sizes[0]});\n`;
670 } else {
671 if (offset.value[0]>0) {
672 ctx.code += `ctx->field->copyn(${left.label} + ${offset.value[0]}, ${right.label}, ${right.sizes[0]});\n`;
673 } else {
674 ctx.code += `ctx->field->copyn(${left.label}, ${right.label}, ${right.sizes[0]});\n`;
675 }
676 }
677 } else {
678 if (offset.value[0]>0) {
679 for (let i=0; i<right.sizes[0]; i++) left.value[offset.value[0] + i] = right.value[i];
680 } else {
681 for (let i=0; i<right.sizes[0]; i++) left.value[i] = right.value[i];
682 }
683 }
684}
685
686function genAssignement(ctx, ast) {
687
688 let lRef;
689 let sels;
690
691 if (ctx.error) return;
692
693 if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast);
694
695 if (ast.values[0].type == "DECLARE") {
696 lRef = gen(ctx, ast.values[0]);
697 if (ctx.error) return;
698 sels = [];
699 } else {
700 lRef = ast.values[0].refId;
701 sels = ast.values[0].selectors;
702 }
703
704
705 const left = ctx.refs[lRef];
706 if (!left) return ctx.throwError(ast, "Variable does not exists: "+ast.values[0].name);
707
708 // Component instantiation is already done.
709 if (left.type == "COMPONENT") return;
710
711 const rRef = gen(ctx, ast.values[1]);
712 if (ctx.error) return;
713
714 if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lRef, sels, rRef);
715
716 if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lRef, sels, rRef);
717
718 return ctx.throwError(ast, "Assigning to invalid");
719}
720
721function genConstraint(ctx, ast) {
722 const aRef = gen(ctx, ast.values[0]);
723 const a = ctx.refs[aRef];
724 if (ctx.error) return;
725 const bRef = gen(ctx, ast.values[1]);
726 const b = ctx.refs[bRef];
727 if (ctx.error) return;
728 const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
729 ctx.code += `ctx->checkConstraint(${a.label}, ${b.label}, "${strErr}");`;
730}
731
732
733function genArray(ctx, ast) {
734 let subSizes;
735 let instantiate = false;
736 if (ast.values.length == 0) return ctx.throwError(ast, "Arrays with zero elements not allowed");
737 const value = [];
738 const refs = [];
739 for (let i=0; i<ast.values.length; i++) {
740 const eRef = gen(ctx, ast.values[i]);
741 const e = ctx.refs[eRef];
742
743 if (i==0) {
744 subSizes = e.sizes;
745 } else {
746 if (!utils.sameSizes(subSizes, e.sizes)) return ctx.throwError(ast, "Heteroeneus array not allowed");
747 }
748 if (e.used) {
749 instantiate = true;
750 }
751 if (!instantiate) {
752 value.push(...e.value);
753 }
754 refs.push(eRef);
755 }
756
757 const newSize = [subSizes[0]*ast.values.length , ...subSizes];
758
759 if (instantiate) {
760 const rRef = newRef(ctx, "BIGINT", "_arr", null, newSize);
761 instantiateRef(ctx, rRef);
762 for (let i=0; i<ast.values.length; i++) {
763 const v = ctx.refs[refs[i]];
764 const r = ctx.refs[rRef];
765 ctx.code += `ctx->field->copyn(${r.label}+${i*subSizes[0]}, ${v.label}, ${subSizes[0]});\n`;
766 }
767 return rRef;
768 } else {
769 const rRef = newRef(ctx, "BIGINT", "_arr", value, newSize);
770 return rRef;
771 }
772
773}
774
775
776function genFunctionCall(ctx, ast) {
777 const params = [];
778 for (let i=0; i<ast.params.length; i++) {
779 const pRef = gen(ctx, ast.params[i]);
780 params.push(ctx.refs[pRef]);
781 }
782
783 const fn = ctx.buildFunction(ast.name, params);
784 if (ctx.error) return;
785
786 if (fn.type == "VARVAL_CONSTSIZE") {
787 const resRef = newRef(ctx, "BIGINT", `_ret${ast.name}Sizes`, null, fn.returnSizes);
788 const res = ctx.refs[resRef];
789 instantiateRef(ctx, resRef);
790
791 ctx.code +=`${fn.fnName}(ctx, ${res.label}`;
792 for (let i=0; i<params.length; i++) {
793 if (params[i].used) ctx.code+=`,${params[i].label}`;
794 }
795 ctx.code+=");\n";
796
797 return resRef;
798 } else {
799 const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes);
800 return res;
801 }
802}
803
804function enterConditionalCode(ctx, ast) {
805 if (!ctx.conditionalCode) {
806 iterateAST(ast, (ast) => {
807 if (ast.type == "OP") {
808 if (["=", "+=", "*=", "PLUSPLUSLEFT", "PLUSPLUSRIGHT", "MINUSMINUSLEFT", "MINUSMINUSRIGHT"].indexOf(ast.op) >= 0) {
809 let refId;
810 refId = ast.values[0].refId;
811 const ref = ctx.refs[refId];
812 instantiateRef(ctx, refId, ref.value);
813 }
814 }
815 });
816 ctx.conditionalCode = 1;
817 } else {
818 ctx.conditionalCode ++;
819 }
820}
821
822function leaveConditionalCode(ctx) {
823 assert(ctx.conditionalCode, "Leaving conditional code too many times");
824 ctx.conditionalCode --;
825 if (!ctx.conditionalCode) {
826 delete ctx.conditionalCode;
827 }
828}
829
830function genFor(ctx, ast) {
831 genForSrcComment(ctx, ast);
832 let inLoop = false;
833 ctx.scopes.push({});
834 gen(ctx, ast.init);
835 if (ctx.error) return;
836
837 let end=false;
838 let condVarRef;
839 let condVar;
840
841
842 const condRef = gen(ctx, ast.condition);
843 if (ctx.error) return;
844
845 const cond = ctx.refs[condRef];
846 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
847
848 if (cond.used) {
849 inLoop = true;
850 enterConditionalCode(ctx, ast);
851 condVarRef = newRef(ctx, "INT", "_cond");
852 condVar = ctx.refs[condVarRef];
853 instantiateRef(ctx, condVarRef);
854
855 ctx.code +=
856 `${condVar.label} = ctx->field->isTrue(${cond.label});\n` +
857 `while (${condVar.label}) {\n`;
858 } else {
859 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
860 if (cond.value[0].isZero()) end=true;
861 }
862
863
864 while (!end) {
865
866 const oldCode = ctx.code;
867 ctx.code = "";
868
869 if (ast.body.type != "BLOCK") genSrcComment(ctx, ast.body);
870 gen(ctx, ast.body);
871 if (ctx.error) return;
872
873 gen(ctx, ast.step);
874 if (ctx.error) return;
875
876 const condRef2 = gen(ctx, ast.condition);
877 if (ctx.error) return;
878
879 const cond2 = ctx.refs[condRef2];
880
881 if (!inLoop) {
882 if (cond2.used) {
883 ctx.code = oldCode + ctx.code;
884 inLoop = true;
885 enterConditionalCode(ctx, ast);
886 condVar = newRef(ctx, "INT", "_cond");
887 instantiateRef(ctx, condVar);
888
889 ctx.code =
890 oldCode +
891 ctx.code +
892 `${condVar.label} = ctx->field->isTrue(${cond2.label});\n` +
893 `while (${condVar.label}) {\n`;
894 } else {
895 ctx.code = oldCode + ctx.code;
896 if (cond2.value[0].isZero()) end=true;
897 }
898 } else {
899 ctx.code =
900 oldCode +
901 utils.ident(
902 ctx.code +
903 `${condVar.label} = ctx->field->isTrue(${cond2.label});\n`);
904 end=true;
905 }
906 }
907 if (inLoop) {
908 ctx.code += "}\n";
909 leaveConditionalCode(ctx);
910 }
911 ctx.scopes.pop();
912}
913
914function genWhile(ctx, ast) {
915 const condition = gen(ctx, ast.condition);
916 if (ctx.error) return;
917 const body = gen(ctx, ast.body);
918 if (ctx.error) return;
919 return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`;
920}
921
922function genCompute(ctx, ast) {
923 const body = gen(ctx, ast.body);
924 if (ctx.error) return;
925 return `{\n${body}\n}\n`;
926}
927
928function genIf(ctx, ast) {
929 genIfSrcComment(ctx, ast);
930 const condRef = gen(ctx, ast.condition);
931 if (ctx.error) return;
932 const cond = ctx.refs[condRef];
933 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
934
935 if (cond.used) {
936 enterConditionalCode(ctx, ast);
937
938 ctx.code += `if (ctx->field->isTrue(${cond.label})) {\n`;
939
940 const oldCode = ctx.code;
941 ctx.code = "";
942
943 gen(ctx, ast.then);
944 if (ctx.error) return;
945
946 ctx.code = oldCode + utils.ident(ctx.code);
947
948 if (ast.else) {
949 ctx.code += "} else {\n";
950 const oldCode = ctx.code;
951 ctx.code = "";
952 gen(ctx, ast.else);
953 if (ctx.error) return;
954 ctx.code = oldCode + utils.ident(ctx.code);
955 }
956
957 ctx.code += "}\n";
958
959 } else {
960 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
961 if (!cond.value[0].isZero()) {
962 gen(ctx, ast.then);
963 } else {
964 if (ast.else) {
965 gen(ctx, ast.else);
966 }
967 }
968 }
969}
970
971
972function genReturn(ctx, ast) {
973 const vRef = gen(ctx, ast.value);
974 const v= ctx.refs[vRef];
975 if (ctx.returnSizes) {
976 if (!utils.sizesEqual(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
977 } else {
978 ctx.returnSizes = v.sizes;
979 }
980 if (ctx.conditionalCode) {
981 instantiateRef(ctx, vRef, v.value);
982 }
983 if (v.used) {
984 ctx.code += `ctx->field->copyn(__retValue, ${v.label}, ${v.sizes[0]});\n`;
985 } else {
986 if (!utils.isDefined(v.value)) return ctx.throwError(ast, "Returning an unknown value");
987 if (!utils.isDefined(ctx.returnValue)) {
988 ctx.returnValue = v.value;
989 }
990 }
991 ctx.code += "goto returnFunc;\n";
992 return vRef;
993}
994
995
996
997function genSignalAssignConstraint(ctx, ast) {
998 const res = genAssignement(ctx, ast);
999 // genConstraint(ctx, ast);
1000 return res;
1001 // return genVarAssignement(ctx, ast);
1002}
1003
1004function genVarAddAssignement(ctx, ast) {
1005 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
1006}
1007
1008function genVarMulAssignement(ctx, ast) {
1009 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
1010}
1011
1012function genOpOp(ctx, ast, op, lr) {
1013
1014 if (ast.values[0].type != "VARIABLE") return ctx.throwError(ast, "incrementing a non variable");
1015
1016 const vRef = ast.values[0].refId;
1017
1018 const vevalRef = gen(ctx, ast.values[0]);
1019 if (ctx.error) return;
1020 const veval = ctx.refs[vevalRef];
1021
1022 if (veval.type != "BIGINT") return ctx.throwError(ast, "incrementing a non variable");
1023
1024 const resRef = newRef(ctx, "BIGINT", "_tmp");
1025 const res = ctx.refs[resRef];
1026 if (veval.used) {
1027 instantiateRef(ctx, resRef);
1028 ctx.code += `ctx->field->${op}(${res.label}, ${veval.label}, &(ctx->field->one));\n`;
1029 } else {
1030 res.value = [ctx.field[op](veval.value[0], bigInt(1))];
1031 }
1032 genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
1033 if (lr == "RIGHT") {
1034 return vevalRef;
1035 } else if (lr == "LEFT") {
1036 return resRef;
1037 }
1038}
1039
1040function genBinaryOp(ctx, ast, op) {
1041 let aRef = gen(ctx, ast.values[0]);
1042 if (ctx.error) return;
1043 let a = ctx.refs[aRef];
1044
1045 let bRef = gen(ctx, ast.values[1]);
1046 if (ctx.error) return;
1047 let b = ctx.refs[bRef];
1048
1049 if ((!a.used)&&(!utils.isDefined(a.value))) return ctx.throwError(ast, "Using a not assigned varialble: ");
1050 if ((!b.used)&&(!utils.isDefined(b.value))) return ctx.throwError(ast, "Using a not assigned varialble: ");
1051 if (!utils.sameSizes(a.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
1052 if (!utils.sameSizes(b.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
1053
1054 let rRef;
1055 if (a.used || b.used) {
1056 if (!a.used) {
1057 aRef = instantiateConstant(ctx, a.value);
1058 a = ctx.refs[aRef];
1059 }
1060 if (!b.used) {
1061 bRef = instantiateConstant(ctx, b.value);
1062 b = ctx.refs[bRef];
1063 }
1064
1065 rRef = newRef(ctx, "BIGINT", "_tmp");
1066 instantiateRef(ctx, rRef);
1067 const r = ctx.refs[rRef];
1068 ctx.code += `ctx->field->${op}(${r.label},${a.label}, ${b.label});\n`;
1069 } else {
1070 rRef = newRef(ctx, "BIGINT", "_tmp", ctx.field[op](a.value[0], b.value[0]));
1071 }
1072 return rRef;
1073}
1074
1075
1076function genSub(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}).add(__P__).sub(bigInt(${b})).mod(__P__)`;
1082}
1083
1084function genDiv(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
1090 return `bigInt(${a}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`;
1091}
1092
1093function genIDiv(ctx, ast) {
1094 const a = gen(ctx, ast.values[0]);
1095 if (ctx.error) return;
1096 const b = gen(ctx, ast.values[1]);
1097 if (ctx.error) return;
1098
1099 return `bigInt(${a}).div( bigInt(${b}))`;
1100}
1101
1102function genExp(ctx, ast) {
1103 const a = gen(ctx, ast.values[0]);
1104 if (ctx.error) return;
1105 const b = gen(ctx, ast.values[1]);
1106 if (ctx.error) return;
1107 return `bigInt(${a}).modPow(bigInt(${b}), __P__)`;
1108}
1109
1110function genBAnd(ctx, ast) {
1111 const a = gen(ctx, ast.values[0]);
1112 if (ctx.error) return;
1113 const b = gen(ctx, ast.values[1]);
1114 if (ctx.error) return;
1115 return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
1116}
1117
1118function genAnd(ctx, ast) {
1119 const a = gen(ctx, ast.values[0]);
1120 if (ctx.error) return;
1121 const b = gen(ctx, ast.values[1]);
1122 if (ctx.error) return;
1123 return `((bigInt(${a}).neq(bigInt(0)) && bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
1124}
1125
1126function genOr(ctx, ast) {
1127 const a = gen(ctx, ast.values[0]);
1128 if (ctx.error) return;
1129 const b = gen(ctx, ast.values[1]);
1130 if (ctx.error) return;
1131 return `((bigInt(${a}).neq(bigInt(0)) || bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
1132}
1133
1134function genShl(ctx, ast) {
1135 const a = gen(ctx, ast.values[0]);
1136 if (ctx.error) return;
1137 const b = gen(ctx, ast.values[1]);
1138 if (ctx.error) return;
1139 return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shl(bigInt(${b})).and(__MASK__)`;
1140}
1141
1142function genShr(ctx, ast) {
1143 const a = gen(ctx, ast.values[0]);
1144 if (ctx.error) return;
1145 const b = gen(ctx, ast.values[1]);
1146 if (ctx.error) return;
1147 return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`;
1148}
1149
1150function genMod(ctx, ast) {
1151 const a = gen(ctx, ast.values[0]);
1152 if (ctx.error) return;
1153 const b = gen(ctx, ast.values[1]);
1154 if (ctx.error) return;
1155 return `bigInt(${a}).mod(bigInt(${b}))`;
1156}
1157
1158function genUMinus(ctx, ast) {
1159 const a = gen(ctx, ast.values[0]);
1160 if (ctx.error) return;
1161 return `__P__.sub(bigInt(${a})).mod(__P__)`;
1162}
1163
1164function genTerCon(ctx, ast) {
1165 const a = gen(ctx, ast.values[0]);
1166 if (ctx.error) return;
1167 const b = gen(ctx, ast.values[1]);
1168 if (ctx.error) return;
1169 const c = gen(ctx, ast.values[2]);
1170 if (ctx.error) return;
1171 return `bigInt(${a}).neq(bigInt(0)) ? (${b}) : (${c})`;
1172}
1173
1174function genInclude(ctx, ast) {
1175 return ast.block ? gen(ctx, ast.block) : "";
1176}
1177
1178