circom/src/gencode.js
src/gencode.jsRaw
1const utils = require("./utils");
2const assert = require("assert");
3const iterateAST = require("./iterateast");
4const Scalar = require("ffjavascript").Scalar;
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 if (!v.sizes) v.sizes = [1,0];
44
45 if (v.type=="BIGINT") {
46 ctx.fnBuilder.defineFrElements(v.label, v.sizes[0]);
47 } else if (v.type=="INT") {
48 ctx.fnBuilder.defineIntElement(v.label);
49 } else if (v.type=="SIZES") {
50 ctx.fnBuilder.defineSizesElement(v.label);
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 idConstant = ctx.addConstant(initValue[i]);
58 ctx.fnBuilder.initializeFrElement(v.label, i, idConstant);
59 }
60 }
61 }
62 }
63}
64
65function createRefs(ctx, ast) {
66 const scopeLabels = [];
67 iterateAST(ast, (ast, level) => {
68 while ((scopeLabels.length>0)&&(!level.startsWith(scopeLabels[scopeLabels.length-1]))) {
69 ctx.scopes.pop();
70 scopeLabels.pop();
71 }
72 if (ast.type == "DECLARE") {
73 if (ctx.scopes[ctx.scopes.length-1][ast.name.name]) return ctx.throwError(ast, `Name already defined: ${ast.name.name}`);
74 for (let i=ctx.scopes.length-2; i>=0; i--) {
75 if (ctx.scopes[i][ast.name.name]) ctx.logWarning(ast, `Shadowing variable: ${ast.name.name}`);
76 }
77 let entry = {};
78 if (ast.declareType == "COMPONENT") {
79 entry.type= "COMPONENT";
80 entry.label = ast.name.name;
81 } else if ((ast.declareType == "SIGNALIN")||
82 (ast.declareType == "SIGNALOUT")||
83 (ast.declareType == "SIGNAL")) {
84 entry.type = "SIGNAL";
85 entry.label = ast.name.name;
86 } else if (ast.declareType == "VARIABLE") {
87 entry.type = "BIGINT";
88 entry.used = false;
89 entry.sizes = null;
90 entry.label = ctx.getUniqueName(ast.name.name);
91 } else {
92 return ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
93 }
94
95 const refId = ctx.refs.length;
96 ctx.refs.push(entry);
97 ast.refId = refId;
98 ctx.scopes[ctx.scopes.length-1][ast.name.name] = refId;
99 } else if (["BLOCK", "FOR", "IF", "WHILE", "COMPUTE"].indexOf(ast.type) >= 0) {
100 scopeLabels.push(level);
101 ctx.scopes.push({});
102 } else if (ast.type == "VARIABLE") {
103 ast.refId = name2ref(ast.name);
104 }
105 });
106
107 function name2ref(n) {
108 for (let i=ctx.scopes.length-1; i>=0; i--) {
109 if (typeof ctx.scopes[i][n] !== "undefined") return ctx.scopes[i][n];
110 }
111 return -1;
112 }
113}
114
115function gen(ctx, ast) {
116 if ((ast.type == "NUMBER") ) {
117 return genNumber(ctx, ast);
118 } else if (ast.type == "VARIABLE") {
119 return genVariable(ctx, ast);
120 } else if (ast.type == "PIN") {
121 return genPin(ctx, ast);
122 } else if (ast.type == "OP") {
123 if (ast.op == "=") {
124 return genAssignement(ctx, ast);
125 } else if (ast.op == "<--") {
126 return genAssignement(ctx, ast);
127 } else if (ast.op == "<==") {
128 return genSignalAssignConstraint(ctx, ast);
129 } else if (ast.op == "===") {
130 return genConstraint(ctx, ast);
131 } else if (ast.op == "+=") {
132 return genVarAddAssignement(ctx, ast);
133 } else if (ast.op == "*=") {
134 return genVarMulAssignement(ctx, ast);
135 } else if (ast.op == "+") {
136 return genOp(ctx, ast, "add", 2);
137 } else if (ast.op == "-") {
138 return genOp(ctx, ast, "sub", 2);
139 } else if (ast.op == "UMINUS") {
140 return genOp(ctx, ast, "neg", 1);
141 } else if (ast.op == "*") {
142 return genOp(ctx, ast, "mul", 2);
143 } else if (ast.op == "%") {
144 return genOp(ctx, ast, "mod", 2);
145 } else if (ast.op == "PLUSPLUSRIGHT") {
146 return genOpOp(ctx, ast, "add", "RIGHT");
147 } else if (ast.op == "PLUSPLUSLEFT") {
148 return genOpOp(ctx, ast, "add", "LEFT");
149 } else if (ast.op == "MINUSMINUSRIGHT") {
150 return genOpOp(ctx, ast, "sub", "RIGHT");
151 } else if (ast.op == "MINUSMINUSLEFT") {
152 return genOpOp(ctx, ast, "sub", "LEFT");
153 } else if (ast.op == "**") {
154 return genOp(ctx, ast, "pow", 2);
155 } else if (ast.op == "/") {
156 return genOp(ctx, ast, "div", 2);
157 } else if (ast.op == "\\") {
158 return genOp(ctx, ast, "idiv", 2);
159 } else if (ast.op == "&") {
160 return genOp(ctx, ast, "band", 2);
161 } else if (ast.op == "|") {
162 return genOp(ctx, ast, "bor", 2);
163 } else if (ast.op == "^") {
164 return genOp(ctx, ast, "bxor", 2);
165 } else if (ast.op == "~") {
166 return genOp(ctx, ast, "bnot", 1);
167 } else if (ast.op == "&&") {
168 return genOp(ctx, ast, "land", 2);
169 } else if (ast.op == "||") {
170 return genOp(ctx, ast, "lor", 2);
171 } else if (ast.op == "!") {
172 return genOp(ctx, ast, "lnot", 1);
173 } else if (ast.op == "<<") {
174 return genOp(ctx, ast, "shl", 2);
175 } else if (ast.op == ">>") {
176 return genOp(ctx, ast, "shr", 2);
177 } else if (ast.op == "<") {
178 return genOp(ctx, ast, "lt", 2, true);
179 } else if (ast.op == ">") {
180 return genOp(ctx, ast, "gt", 2, true);
181 } else if (ast.op == "<=") {
182 return genOp(ctx, ast, "leq", 2, true);
183 } else if (ast.op == ">=") {
184 return genOp(ctx, ast, "geq", 2, true);
185 } else if (ast.op == "==") {
186 return genOp(ctx, ast, "eq", 2, true);
187 } else if (ast.op == "!=") {
188 return genOp(ctx, ast, "neq", 2, true);
189 } else if (ast.op == "?") {
190 return genTerCon(ctx, ast);
191 } else {
192 ctx.throwError(ast, "Invalid operation: " + ast.op);
193 }
194 } else if (ast.type == "DECLARE") {
195 if (ast.declareType == "COMPONENT") {
196 return genDeclareComponent(ctx, ast);
197 } else if ((ast.declareType == "SIGNALIN")||
198 (ast.declareType == "SIGNALOUT")||
199 (ast.declareType == "SIGNAL")) {
200 return genDeclareSignal(ctx, ast);
201 } else if (ast.declareType == "VARIABLE") {
202 return genDeclareVariable(ctx, ast);
203 } else {
204 ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
205 }
206 } else if (ast.type == "FUNCTIONCALL") {
207 return genFunctionCall(ctx, ast);
208 } else if (ast.type == "BLOCK") {
209 return genBlock(ctx, ast);
210 } else if (ast.type == "COMPUTE") {
211 return gen(ctx, ast.body);
212 } else if (ast.type == "FOR") {
213 return genLoop(ctx, ast);
214 } else if (ast.type == "WHILE") {
215 return genLoop(ctx, ast);
216 } else if (ast.type == "IF") {
217 return genIf(ctx, ast);
218 } else if (ast.type == "RETURN") {
219 return genReturn(ctx, ast);
220 } else if (ast.type == "INCLUDE") {
221 return genInclude(ctx, ast);
222 } else if (ast.type == "ARRAY") {
223 return genArray(ctx, ast);
224 } else {
225 ctx.throwError(ast, "GEN -> Invalid AST node type: " + ast.type);
226 }
227}
228
229function genBlock(ctx, ast) {
230 ctx.scopes.push({});
231 let res = null;
232 for (let i=0; i<ast.statements.length; i++) {
233 if (["BLOCK", "COMPUTE", "FOR", "WHILE", "IF"].indexOf(ast.statements[i].type)<0) {
234 genSrcComment(ctx, ast.statements[i]);
235 }
236 res = gen(ctx, ast.statements[i]);
237 if (ctx.error) return;
238 }
239 ctx.scopes.pop();
240 return res;
241}
242
243function getSource(ctx, ast) {
244 let codes = [];
245 const fl= ast.first_line-1;
246 const ll = ast.last_line-1;
247 const fc = ast.first_column;
248 const lc = ast.last_column;
249 for (let i=fl; i<=ll; i++) {
250 const p1 = i==fl ? fc : 0;
251 const p2 = i==ll ? lc : -1;
252 codes.push(ctx.includedFiles[ctx.fileName][i].slice(p1, p2>=0 ? p2 : undefined));
253 }
254 return codes.join("\n");
255}
256
257function genSrcComment(ctx, ast) {
258 const code = getSource(ctx, ast);
259 ctx.codeBuilder.addComment(code);
260}
261
262function genLoopSrcComment(ctx, ast) {
263 if (ast.type == "FOR") {
264 const init = getSource(ctx, ast.init);
265 const condition = getSource(ctx, ast.condition);
266 const step = getSource(ctx, ast.step);
267 ctx.codeBuilder.addComment(`for (${init};${condition};${step})`);
268 } else if (ast.type == "WHILE") {
269 const condition = getSource(ctx, ast.condition);
270 ctx.codeBuilder.addComment(`while (${condition})`);
271 } else {
272 assert(false, "Invalid loop type: "+ ast.type);
273 }
274}
275
276function genIfSrcComment(ctx, ast) {
277 const condition = getSource(ctx, ast.condition);
278 ctx.codeBuilder.addComment(`if (${condition})`);
279}
280
281
282function genDeclareComponent(ctx, ast) {
283 return ast.refId;
284}
285
286function genDeclareSignal(ctx, ast) {
287
288 const v = ctx.refs[ast.refId];
289
290 let sizes;
291 if (ast.name.selectors.length>0) {
292 sizes=[];
293 for (let i=0; i< ast.name.selectors.length; i++) {
294 const sizeRef = gen(ctx, ast.name.selectors[i]);
295 const size = ctx.refs[sizeRef];
296 if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
297 if (size.used) return ctx.throwError(ast, "Signal size variables not allowed");
298 sizes.push(Scalar.toNumber(size.value[0]));
299 }
300 sizes = utils.accSizes(sizes);
301 } else {
302 sizes = [1,0];
303 }
304
305 if ((!v.sizes)&&(sizes)) {
306 v.sizes = sizes;
307 }
308
309 if (v.sizes) {
310 if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a signal with different sized");
311 }
312
313 return ast.refId;
314}
315
316function genDeclareVariable(ctx, ast) {
317
318
319 const v = ctx.refs[ast.refId];
320
321 let sizes;
322 if (ast.name.selectors.length>0) {
323 sizes=[];
324 for (let i=0; i< ast.name.selectors.length; i++) {
325 const sizeRef = gen(ctx, ast.name.selectors[i]);
326 const size = ctx.refs[sizeRef];
327 if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
328 if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
329 sizes.push(Scalar.toNumber(size.value[0]));
330 }
331 sizes = utils.accSizes(sizes);
332 } else {
333 sizes = [1,0];
334 }
335
336 if ((!v.sizes)&&(sizes)) {
337 v.sizes = sizes;
338 v.value = new Array(sizes[0]);
339 }
340
341 if (v.sizes) {
342 if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a var with different sized");
343 }
344
345 return ast.refId;
346}
347
348function genNumber(ctx, ast) {
349 return newRef(ctx, "BIGINT", "_num", ctx.F.e(ast.value));
350}
351
352
353
354function genGetOffset(ctx, refOffset, vSizes, sels) {
355
356 let offsets = [];
357 let offset;
358
359 let isConstant = true;
360 let constant = 0;
361 let isRef = false;
362
363 if (refOffset) {
364 offset = ctx.refs[refOffset];
365 if (offset.used) {
366 offsets.push([["RI", offset.label], ["V", 1]]);
367 isRef = true;
368 isConstant = false;
369 } else {
370 offsets.push([["V", parseInt(offset.value)], ["V", 1]]);
371 constant = parseInt(offset.value);
372 }
373 }
374
375 if ((sels)&&(sels.length>0)) {
376
377 let iSizes;
378 if (Array.isArray(vSizes)) {
379 iSizes = {
380 used: false,
381 sizes: vSizes
382 };
383 } else {
384 iSizes = ctx.refs[vSizes];
385 }
386
387 for (let i=0; i<sels.length; i++) {
388 let idx, sze;
389 const idxRef = gen(ctx, sels[i]);
390 const iIdx = ctx.refs[idxRef];
391 if (iIdx.used) {
392 idx = ["R", iIdx.label];
393 } else {
394 idx = ["V", parseInt(iIdx.value[0])];
395 }
396 if (iSizes.used) {
397 sze = ["RS", iSizes.label, i+1 ];
398 } else {
399 sze = ["V", iSizes.sizes[i+1] ];
400 }
401 offsets.push([idx, sze]);
402 if ((idx[0] == "V")&&(sze[0] == "V")&&(isConstant)) {
403 constant += idx[1]*sze[1];
404 if (idx[1]*sze[1] > 0) isRef = false;
405 } else {
406 isConstant = false;
407 isRef = false;
408 }
409 }
410 }
411
412 if (isConstant) {
413 const o = newRef(ctx, "INT", "_offset", constant);
414 return o;
415 }
416 if (isRef) {
417 return refOffset;
418 }
419 const resRef = newRef(ctx, "INT", "_offset");
420 instantiateRef(ctx, resRef);
421
422 const res = ctx.refs[resRef];
423
424 ctx.codeBuilder.calcOffset(res.label, offsets);
425 return resRef;
426}
427
428function genVariable(ctx, ast) {
429 const v = ctx.refs[ast.refId];
430
431 const l = ast.selectors ? ast.selectors.length : 0;
432
433 if (v.type == "SIGNAL") {
434 let vOffset;
435 if (l>0) {
436 const vsOffset = genGetSignalOffset(ctx, -1, ast.name);
437 const vsSizes = genGetSignalSizes(ctx, -1, ast.name);
438 vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
439 } else {
440 vOffset = genGetSignalOffset(ctx, -1, ast.name);
441 }
442
443 const sizes = v.sizes.slice(l);
444
445 const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
446 const res = ctx.refs[resRef];
447 instantiateRef(ctx, resRef);
448 ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset), sizes[0]);
449 return resRef;
450 } else if (v.type == "BIGINT") {
451 const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
452 const offset = ctx.refs[refOffset];
453 let ot;
454 if (offset.type == "BIGINT") {
455 ot = "R";
456 } else if (offset.type == "INT") {
457 ot= "RI";
458 } else {
459 assert(false);
460 }
461 if (v.used) {
462 if (offset.used) {
463 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
464 const res = ctx.refs[refRes];
465 res.used = true;
466 ctx.fnBuilder.definePFrElement(res.label);
467 ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
468 return refRes;
469 } else if ((offset.value[0]>0)||(l>0)) {
470 const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
471 const res = ctx.refs[refRes];
472 res.used = true;
473 ctx.fnBuilder.definePFrElement(res.label);
474 ctx.codeBuilder.assign(res.label, ["R", v.label], ["V", offset.value[0]]);
475 return refRes;
476 } else {
477 return ast.refId;
478 }
479 } else {
480 if (offset.used) {
481 instantiateRef(ctx, ast.refId, v.value);
482 const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
483 const res = ctx.refs[resRef];
484 res.used = true;
485 ctx.fnBuilder.definePFrElement(res.label);
486 ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
487 return resRef;
488 } else {
489 // return newSubRef(ctx, ast.name, ast.selectors);
490 return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l));
491 }
492 }
493 }
494}
495
496
497function genPin(ctx, ast) {
498 let vcIdx;
499 if (ast.component.selectors.length>0) {
500 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.component.name);
501 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.component.name);
502 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors );
503 } else {
504 vcIdx = genGetSubComponentOffset(ctx, -1, ast.component.name);
505 }
506
507 let vsIdx;
508 if (ast.pin.selectors.length>0) {
509 const vsOffset = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
510 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name);
511 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors );
512 } else {
513 vsIdx = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
514 }
515
516 const l = ast.selectors ? ast.selectors.length : 0;
517
518 const sizes = [1,0]; // TODO, Treat array
519
520 const resRef = newRef(ctx, "BIGINT", "_sigValue", null, sizes);
521 const res = ctx.refs[resRef];
522 instantiateRef(ctx, resRef);
523 ctx.codeBuilder.getSignal(
524 res.label,
525 toRefA_Int1(ctx, ast.component, vcIdx),
526 toRefA_Int1(ctx, ast.pin, vsIdx),
527 sizes[0]
528 );
529 return resRef;
530}
531
532function genGetSubComponentOffset(ctx, cIdxRef, label) {
533 const refOffset = newRef(ctx, "INT", "_compIdx");
534 const offset = ctx.refs[refOffset];
535 instantiateRef(ctx, refOffset);
536
537 const h = utils.fnvHash(label);
538 let c;
539 if (cIdxRef>=0) {
540 const cIdx = ctx.refs[cIdxRef];
541 if (cIdx.used) {
542 if (cIdx.type == "BIGINT") {
543 c = ["R", cIdx.label];
544 } else if (cIdx.type == "INT") {
545 c = ["RI", cIdx.label];
546 } else {
547 assert(false);
548 }
549 } else {
550 c = ["V", cIdx.value[0]];
551 }
552 } else {
553 c = ["CC"];
554 }
555 ctx.codeBuilder.getSubComponentOffset(offset.label, c, h, label);
556 return refOffset;
557}
558
559function genGetSubComponentSizes(ctx, cIdxRef, label) {
560 const sizesRef = newRef(ctx, "SIZES", "_compSizes");
561 const sizes = ctx.refs[sizesRef];
562 instantiateRef(ctx, sizesRef);
563
564 const h = utils.fnvHash(label);
565 let c;
566 if (cIdxRef>=0) {
567 const cIdx = ctx.refs[cIdxRef];
568 if (cIdx.used) {
569 if (cIdx.type == "BIGINT") {
570 c = ["R", cIdx.label];
571 } else if (cIdx.type == "INT") {
572 c = ["RI", cIdx.label];
573 } else {
574 assert(false);
575 }
576 } else {
577 c = ["V", cIdx.value[0]];
578 }
579 } else {
580 c = ["CC"];
581 }
582 ctx.codeBuilder.getSubComponentSizes(sizes.label, c, h, label);
583 return sizesRef;
584}
585
586function genGetSignalOffset(ctx, cIdxRef, label) {
587
588 let constCIdx = null;
589 if (cIdxRef>=0) {
590 const cIdx = ctx.refs[cIdxRef];
591 if (!cIdx.used) {
592 constCIdx = cIdx.value.toString()+"_"+label;
593 }
594 } else {
595 constCIdx = "_cIdx_"+label;
596 }
597 if (constCIdx && ctx.getSignalOffsetCache[constCIdx]) return ctx.getSignalOffsetCache[constCIdx];
598
599 const refOffset = newRef(ctx, "INT", "_" + label + "_sigIdx_");
600 const offset = ctx.refs[refOffset];
601 instantiateRef(ctx, refOffset);
602
603 const h = utils.fnvHash(label);
604 let c;
605 if (cIdxRef>=0) {
606 const cIdx = ctx.refs[cIdxRef];
607 if (cIdx.used) {
608 if (cIdx.type == "BIGINT") {
609 c = ["R", cIdx.label];
610 } else if (cIdx.type == "INT") {
611 c = ["RI", cIdx.label];
612 } else {
613 assert(false);
614 }
615 } else {
616 c = ["V", cIdx.value[0]];
617 }
618 } else {
619 c = ["CC"];
620 }
621 if (constCIdx) {
622 ctx.fnBuilder.initializeSignalOffset(offset.label, c, h, label);
623 ctx.getSignalOffsetCache[constCIdx] = refOffset;
624 } else {
625 ctx.codeBuilder.getSignalOffset(offset.label, c, h, label);
626 }
627 return refOffset;
628}
629
630function genGetSignalSizes(ctx, cIdxRef, label) {
631 let constCIdx = null;
632 if (cIdxRef>=0) {
633 const cIdx = ctx.refs[cIdxRef];
634 if (utils.isDefined(cIdx.value)) {
635 constCIdx = cIdx.value.toString()+"_"+label;
636 }
637 } else {
638 constCIdx = "_cIdx_"+label;
639 }
640 if (constCIdx && ctx.getSignalSizesCache[constCIdx]) return ctx.getSignalSizesCache[constCIdx];
641
642
643 const refSizes = newRef(ctx, "SIZES", "_sigSizes_"+label);
644 const sizes = ctx.refs[refSizes];
645 instantiateRef(ctx, refSizes);
646
647 let c;
648 if (cIdxRef>=0) {
649 const cIdx = ctx.refs[cIdxRef];
650 if (cIdx.used) {
651 if (cIdx.type == "BIGINT") {
652 c = ["R", cIdx.label];
653 } else if (cIdx.type == "INT") {
654 c = ["RI", cIdx.label];
655 } else {
656 assert(false);
657 }
658 } else {
659 c = ["V", cIdx.value[0]];
660 }
661 } else {
662 c = ["CC"];
663 }
664 const h = utils.fnvHash(label);
665 if (constCIdx) {
666 ctx.fnBuilder.initializeSignalSizes(sizes.label, c, h, label);
667 ctx.getSignalSizesCache[constCIdx] = refSizes;
668 } else {
669 ctx.codeBuilder.getSignalSizes(sizes.label, c, h, label);
670 }
671 return refSizes;
672}
673
674function genPinAssignement(ctx, ast) {
675 let vcIdx;
676 if (ast.values[0].component.selectors.length>0) {
677 const vcOffset = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
678 const vcSizes = genGetSubComponentSizes(ctx, -1, ast.values[0].component.name);
679 vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors );
680 } else {
681 vcIdx = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
682 }
683
684 let vsIdx;
685 if (ast.values[0].pin.selectors.length>0) {
686 const vsOffset = genGetSignalOffset(ctx, vcIdx, ast.values[0].pin.name);
687 const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name);
688 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors );
689 } else {
690 vsIdx = genGetSignalOffset(ctx, vcIdx, ast.values[0].pin.name);
691 }
692
693 const vVal = gen(ctx, ast.values[1]);
694
695 ctx.codeBuilder.setSignal(
696 toRefA_Int1(ctx, ast.values[0].component, vcIdx),
697 toRefA_Int1(ctx, ast.values[0].pin, vsIdx),
698 toRefA_Fr1(ctx, ast.values[1], vVal)
699 );
700
701 return vVal;
702}
703
704function genSignalAssignmen(ctx, ast, lName, sels, rName) {
705 let vsIdx;
706 const signal = ctx.refs[lName];
707 if (sels.length>0) {
708 const vsOffset = genGetSignalOffset(ctx, -1, signal.label);
709 const vsSizes = genGetSignalSizes(ctx, -1, signal.label);
710 vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels );
711 } else {
712 vsIdx = genGetSignalOffset(ctx, -1, signal.label);
713 }
714
715 ctx.codeBuilder.setSignal(
716 ["CC"],
717 toRefA_Int1(ctx, ast.values[0], vsIdx),
718 toRefA_Fr1(ctx, ast.values[1], rName)
719 );
720}
721
722function genVarAssignment(ctx, ast, lRef, sels, rRef) {
723
724 const left = ctx.refs[lRef];
725 const right = ctx.refs[rRef];
726 if (!utils.isDefined(left.sizes)) {
727 left.sizes = right.sizes;
728 left.value = new Array(left.sizes[0]);
729 }
730 if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return ctx.throwError(ast, "Sizes do not match");
731
732 const oRef = genGetOffset(ctx, 0, left.sizes, sels);
733 const offset = ctx.refs[oRef];
734
735 let instantiated=false;
736 if (left.used) {
737 instantiateRef(ctx, rRef, right.value);
738 instantiated=true;
739 } else if (right.used) {
740 if (sels.length == 0) {
741 instantiateRef(ctx,lRef);
742 } else {
743 instantiateRef(ctx,lRef, left.value);
744 }
745 instantiated=true;
746 } else if (offset.used) {
747 instantiateRef(ctx, rRef, right.value);
748 if (sels.length == 0) {
749 instantiateRef(ctx,lRef);
750 } else {
751 instantiateRef(ctx,lRef, left.value);
752 }
753 instantiated=true;
754 }
755
756 if (instantiated) {
757 if (offset.used) {
758 let ot;
759 if (offset.type == "BIGINT") {
760 ot = "R";
761 } else if (offset.type == "INT") {
762 ot= "RI";
763 } else {
764 assert(false);
765 }
766 ctx.codeBuilder.copyN(left.label, [ot, offset.label], ["R", right.label], right.sizes[0]);
767 } else {
768 ctx.codeBuilder.copyN(left.label, ["V", offset.value[0]], ["R", right.label], right.sizes[0]);
769 }
770 } else {
771 if (offset.value[0]>0) {
772 for (let i=0; i<right.sizes[0]; i++) left.value[offset.value[0] + i] = right.value[i];
773 } else {
774 for (let i=0; i<right.sizes[0]; i++) left.value[i] = right.value[i];
775 }
776 }
777}
778
779function genAssignement(ctx, ast) {
780
781 let lRef;
782 let sels;
783
784 if (ctx.error) return;
785
786 if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast);
787
788 if (ast.values[0].type == "DECLARE") {
789 lRef = gen(ctx, ast.values[0]);
790 if (ctx.error) return;
791 sels = [];
792 } else {
793 lRef = ast.values[0].refId;
794 sels = ast.values[0].selectors;
795 }
796
797
798 const left = ctx.refs[lRef];
799 if (!left) return ctx.throwError(ast, "Variable does not exists: "+ast.values[0].name);
800
801 // Component instantiation is already done.
802 if (left.type == "COMPONENT") return;
803
804 const rRef = gen(ctx, ast.values[1]);
805 if (ctx.error) return;
806
807 if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lRef, sels, rRef);
808
809 if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lRef, sels, rRef);
810
811 return ctx.throwError(ast, "Assigning to invalid");
812}
813
814function toRefA_Fr1(ctx, ast, aRef) {
815 const a = ctx.refs[aRef];
816 if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
817 if (a.used) {
818 if (a.type == "BIGINT") {
819 return ["R", a.label];
820 } else {
821 assert(false);
822 }
823 } else {
824 return ["C", ctx.addConstant(a.value[0])];
825 }
826}
827
828function toRefA_Int1(ctx, ast, aRef) {
829 if (aRef <0) return ["CC"];
830 const a = ctx.refs[aRef];
831 if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
832 if (a.used) {
833 if (a.type == "INT") {
834 return ["RI", a.label];
835 } else if (a.type == "BIGINT") {
836 return ["R", a.label];
837 } else {
838 assert(false);
839 }
840 } else {
841 return ["V", a.value[0]];
842 }
843}
844
845
846function genConstraint(ctx, ast) {
847 const aRef = gen(ctx, ast.values[0]);
848 if (ctx.error) return;
849 const bRef = gen(ctx, ast.values[1]);
850 if (ctx.error) return;
851 const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
852
853 ctx.codeBuilder.checkConstraint(toRefA_Fr1(ctx, ast.values[0], aRef), toRefA_Fr1(ctx, ast.values[1], bRef), strErr);
854}
855
856
857function genArray(ctx, ast) {
858 let subSizes;
859 let instantiate = false;
860 if (ast.values.length == 0) return ctx.throwError(ast, "Arrays with zero elements not allowed");
861 const value = [];
862 const refs = [];
863 for (let i=0; i<ast.values.length; i++) {
864 const eRef = gen(ctx, ast.values[i]);
865 const e = ctx.refs[eRef];
866
867 if (i==0) {
868 subSizes = e.sizes;
869 } else {
870 if (!utils.sameSizes(subSizes, e.sizes)) return ctx.throwError(ast, "Heteroeneus array not allowed");
871 }
872 if (e.used) {
873 instantiate = true;
874 }
875 if (!instantiate) {
876 value.push(...e.value);
877 }
878 refs.push(eRef);
879 }
880
881 const newSize = [subSizes[0]*ast.values.length , ...subSizes];
882
883 if (instantiate) {
884 const rRef = newRef(ctx, "BIGINT", "_arr", null, newSize);
885 instantiateRef(ctx, rRef);
886 for (let i=0; i<ast.values.length; i++) {
887 const v = ctx.refs[refs[i]];
888 const r = ctx.refs[rRef];
889 ctx.codeBuilder.copyN(r.label, ["V", i*subSizes[0]], ["R", v.label], subSizes[0]);
890 }
891 return rRef;
892 } else {
893 const rRef = newRef(ctx, "BIGINT", "_arr", value, newSize);
894 return rRef;
895 }
896
897}
898
899
900function genFunctionCall(ctx, ast) {
901 if (ast.name == "log") {
902 const vRef = gen(ctx, ast.params[0]);
903 ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
904 return vRef;
905 }
906 if (ast.name == "assert") {
907 const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
908 const vRef = gen(ctx, ast.params[0]);
909 ctx.codeBuilder.checkAssert(toRefA_Fr1(ctx, ast.params[0], vRef), strErr);
910 return vRef;
911 }
912 const params = [];
913 for (let i=0; i<ast.params.length; i++) {
914 const pRef = gen(ctx, ast.params[i]);
915 params.push(ctx.refs[pRef]);
916 }
917
918 const fn = ctx.buildFunction(ast.name, params);
919 if (ctx.error) return;
920
921 if (fn.type == "VARVAL_CONSTSIZE") {
922 const resRef = newRef(ctx, "BIGINT", `_ret${ast.name}`, null, fn.returnSizes);
923 const res = ctx.refs[resRef];
924 instantiateRef(ctx, resRef);
925
926 const paramLabels = [];
927 for (let i=0; i<params.length; i++) {
928 if (params[i].used) paramLabels.push(params[i].label);
929 }
930
931 ctx.codeBuilder.fnCall(fn.fnName, res.label, paramLabels);
932
933 return resRef;
934 } else {
935 const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes);
936 return res;
937 }
938}
939
940function enterConditionalCode(ctx, ast) {
941 if (!ctx.conditionalCode) {
942 iterateAST(ast, (ast) => {
943 if (ast.type == "OP") {
944 if (["=", "+=", "*=", "PLUSPLUSLEFT", "PLUSPLUSRIGHT", "MINUSMINUSLEFT", "MINUSMINUSRIGHT"].indexOf(ast.op) >= 0) {
945 let refId;
946 refId = ast.values[0].refId;
947 const ref = ctx.refs[refId];
948 instantiateRef(ctx, refId, ref.value);
949 }
950 }
951 });
952 ctx.conditionalCode = 1;
953 } else {
954 ctx.conditionalCode ++;
955 }
956}
957
958function leaveConditionalCode(ctx) {
959 assert(ctx.conditionalCode, "Leaving conditional code too many times");
960 ctx.conditionalCode --;
961 if (!ctx.conditionalCode) {
962 delete ctx.conditionalCode;
963 }
964}
965
966function genLoop(ctx, ast) {
967 genLoopSrcComment(ctx, ast);
968 let inLoop = false;
969
970 if (ast.init) {
971 gen(ctx, ast.init);
972 if (ctx.error) return;
973 }
974
975 let end=false;
976
977 let loopCondRef;
978 let loopCond;
979 let bodyCode;
980
981
982 const condRef = gen(ctx, ast.condition);
983 if (ctx.error) return;
984
985 const cond = ctx.refs[condRef];
986 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genLoop: Operation cannot be done on an array");
987
988 if (cond.used) {
989 inLoop = true;
990 enterConditionalCode(ctx, ast);
991
992 loopCondRef = newRef(ctx, "BIGINT", "_loopCond");
993 loopCond = ctx.refs[loopCondRef];
994 loopCond.used = true;
995 ctx.fnBuilder.definePFrElement(loopCond.label);
996 ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]);
997 } else {
998 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
999 if (ctx.F.isZero(cond.value[0])) end=true;
1000 }
1001
1002
1003 while (!end) {
1004
1005 const oldCodeBuilder = ctx.codeBuilder;
1006 ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1007
1008 if (ast.body.type != "BLOCK") genSrcComment(ctx, ast.body);
1009 gen(ctx, ast.body);
1010 if (ctx.error) return;
1011
1012 if (ast.step) {
1013 gen(ctx, ast.step);
1014 if (ctx.error) return;
1015 }
1016
1017 const condRef2 = gen(ctx, ast.condition);
1018 if (ctx.error) return;
1019
1020 const cond2 = ctx.refs[condRef2];
1021
1022 if ((!cond2.used) &&(ctx.codeBuilder.hasCode())) {
1023 instantiateRef(ctx, condRef2, cond2.value);
1024 }
1025
1026 if (!inLoop) {
1027 if (cond2.used) {
1028 oldCodeBuilder.concat(ctx.codeBuilder);
1029 ctx.codeBuilder = oldCodeBuilder;
1030 inLoop = true;
1031 enterConditionalCode(ctx, ast);
1032
1033 loopCondRef = newRef(ctx, "BIGINT", "_loopCond");
1034 loopCond = ctx.refs[loopCondRef];
1035 loopCond.used = true;
1036 ctx.fnBuilder.definePFrElement(loopCond.label);
1037 ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
1038
1039 } else {
1040 oldCodeBuilder.concat(ctx.codeBuilder);
1041 ctx.codeBuilder = oldCodeBuilder;
1042 if (ctx.F.isZero(cond2.value[0])) end=true;
1043 }
1044 } else {
1045 ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
1046 bodyCode = ctx.codeBuilder;
1047 ctx.codeBuilder = oldCodeBuilder;
1048 end=true;
1049 }
1050 }
1051 if (inLoop) {
1052 ctx.codeBuilder.addLoop(loopCond.label, bodyCode);
1053 leaveConditionalCode(ctx);
1054 }
1055 ctx.scopes.pop();
1056}
1057
1058function genIf(ctx, ast) {
1059 genIfSrcComment(ctx, ast);
1060 const condRef = gen(ctx, ast.condition);
1061 if (ctx.error) return;
1062 const cond = ctx.refs[condRef];
1063 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genIf: Operation cannot be done on an array");
1064
1065 if (cond.used) {
1066 let thenCode, elseCode;
1067 enterConditionalCode(ctx, ast);
1068
1069 const oldCodeBuilder = ctx.codeBuilder;
1070 ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1071
1072 gen(ctx, ast.then);
1073 if (ctx.error) return;
1074
1075 thenCode = ctx.codeBuilder;
1076
1077 if (ast.else) {
1078 ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1079 gen(ctx, ast.else);
1080 if (ctx.error) return;
1081 elseCode = ctx.codeBuilder;
1082 }
1083
1084 ctx.codeBuilder = oldCodeBuilder;
1085 ctx.codeBuilder.addIf(cond.label, thenCode, elseCode);
1086
1087 leaveConditionalCode(ctx);
1088
1089 } else {
1090 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
1091 if (!ctx.F.isZero(cond.value[0])) {
1092 gen(ctx, ast.then);
1093 } else {
1094 if (ast.else) {
1095 gen(ctx, ast.else);
1096 }
1097 }
1098 }
1099}
1100
1101
1102function genReturn(ctx, ast) {
1103 const vRef = gen(ctx, ast.value);
1104 const v= ctx.refs[vRef];
1105 if (ctx.returnSizes) {
1106 if (!utils.sameSizes(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
1107 } else {
1108 ctx.returnSizes = v.sizes;
1109 }
1110 if (ctx.conditionalCode) {
1111 instantiateRef(ctx, vRef, v.value);
1112 }
1113 if (v.used) {
1114 ctx.codeBuilder.copyNRet(["R", v.label], v.sizes[0]);
1115 } else {
1116 if (!utils.isDefined(v.value)) return ctx.throwError(ast, "Returning an unknown value");
1117 if (!utils.isDefined(ctx.returnValue)) {
1118 ctx.returnValue = v.value;
1119 }
1120 }
1121 ctx.codeBuilder.ret();
1122 return vRef;
1123}
1124
1125
1126
1127function genSignalAssignConstraint(ctx, ast) {
1128 const res = genAssignement(ctx, ast);
1129 // genConstraint(ctx, ast);
1130 return res;
1131 // return genVarAssignement(ctx, ast);
1132}
1133
1134function genVarAddAssignement(ctx, ast) {
1135 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
1136}
1137
1138function genVarMulAssignement(ctx, ast) {
1139 return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
1140}
1141
1142function genOpOp(ctx, ast, op, lr) {
1143
1144 if (ast.values[0].type != "VARIABLE") return ctx.throwError(ast, "incrementing a non variable");
1145
1146 const vRef = ast.values[0].refId;
1147
1148 const vevalRef = gen(ctx, ast.values[0]);
1149 if (ctx.error) return;
1150 const veval = ctx.refs[vevalRef];
1151
1152 if (veval.type != "BIGINT") return ctx.throwError(ast, "incrementing a non variable");
1153
1154 const resRef = newRef(ctx, "BIGINT", "_tmp");
1155 const res = ctx.refs[resRef];
1156 if (veval.used) {
1157 instantiateRef(ctx, resRef);
1158 ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(ctx.F.one)]]);
1159 } else {
1160 res.value = [ctx.F[op](veval.value[0], ctx.F.one)];
1161 }
1162 genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
1163 if (lr == "RIGHT") {
1164 return vevalRef;
1165 } else if (lr == "LEFT") {
1166 return resRef;
1167 }
1168}
1169
1170function genOp(ctx, ast, op, nOps, adjustBool) {
1171 const vals = [];
1172 const valRefs = [];
1173
1174 var anyUsed=false;
1175
1176 for (let i=0; i<nOps; i++) {
1177 const ref = gen(ctx, ast.values[i]);
1178 if (ctx.error) return;
1179 let v = ctx.refs[ref];
1180 valRefs.push(ref);
1181 vals.push(v);
1182
1183 if (!utils.sameSizes(v.sizes, [1,0])) {
1184 console.log("xx");
1185 console.log(i);
1186 console.log(v);
1187 return ctx.throwError(ast, "genOp2: Operation cannot be done on an array");
1188 }
1189 if ( (!v.used)
1190 &&( (!utils.isDefined(v.value))
1191 ||(!utils.isDefined(v.value[0]))))
1192 return ctx.throwError(ast, "Using a not assigned varialble: ");
1193
1194 if (v.used) anyUsed=true;
1195 }
1196
1197 let rRef;
1198 if (anyUsed) {
1199 const params = [];
1200 for (let i=0; i<nOps; i++) {
1201 params.push(toRefA_Fr1(ctx, ast.values[i], valRefs[i]));
1202 }
1203
1204 rRef = newRef(ctx, "BIGINT", "_tmp");
1205 instantiateRef(ctx, rRef);
1206 const r = ctx.refs[rRef];
1207 ctx.codeBuilder.fieldOp(r.label, op, params);
1208 } else {
1209 const params = [];
1210 for (let i=0; i<nOps; i++) {
1211 params.push(ctx.F.e(vals[i].value[0]));
1212 }
1213
1214 rRef = newRef(ctx, "BIGINT", "_tmp", adjustBool ? (ctx.F[op](...params)?ctx.F.one:ctx.F.zero) : ctx.F[op](...params));
1215 }
1216 return rRef;
1217}
1218
1219
1220function genTerCon(ctx, ast) {
1221 const condRef = gen(ctx, ast.values[0]);
1222 if (ctx.error) return;
1223 const cond = ctx.refs[condRef];
1224 if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "genTer: Operation cannot be done on an array");
1225
1226 if (cond.used) {
1227 let thenCode, elseCode;
1228 enterConditionalCode(ctx, ast);
1229
1230 const rLabel = ctx.getUniqueName("_ter");
1231
1232 ctx.fnBuilder.definePFrElement(rLabel);
1233
1234 const oldCodeBuilder = ctx.codeBuilder;
1235 ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1236
1237 const thenRef = gen(ctx, ast.values[1]);
1238 if (ctx.error) return;
1239 const then = ctx.refs[thenRef];
1240
1241 let t;
1242 if (then.used) {
1243 t = ["R", then.label];
1244 } else {
1245 if (then.sizes[0] == 1) {
1246 t = ["C", ctx.addConstant(then.value[0])];
1247 } else {
1248 instantiateRef(ctx, thenRef, then.value);
1249 t = ["R", then.label];
1250 }
1251 }
1252
1253 ctx.codeBuilder.assign(rLabel, t, ["V", 0]);
1254
1255 thenCode = ctx.codeBuilder;
1256 ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1257
1258 const elseRef = gen(ctx, ast.values[2]);
1259 if (ctx.error) return;
1260 const els = ctx.refs[elseRef];
1261
1262 let e;
1263 if (els.used) {
1264 e = ["R", els.label];
1265 } else {
1266 if (els.sizes[0] == 1) {
1267 e = ["C", ctx.addConstant(els.value[0])];
1268 } else {
1269 instantiateRef(ctx, elseRef, els.value);
1270 e = ["R", els.label];
1271 }
1272 }
1273
1274 ctx.codeBuilder.assign(rLabel, e, ["V", 0]);
1275 elseCode = ctx.codeBuilder;
1276
1277 ctx.codeBuilder = oldCodeBuilder;
1278
1279 ctx.codeBuilder.addIf(cond.label, thenCode, elseCode);
1280
1281
1282 if (!utils.sameSizes(then.sizes, els.sizes)) return ctx.throwError(ast, "Ternary op must return the same sizes");
1283
1284 const refId = ctx.refs.length;
1285 ctx.refs.push({
1286 type: "BIGINT",
1287 sizes: then.sizes,
1288 used: true,
1289 label: rLabel
1290 });
1291
1292 return refId;
1293
1294 } else {
1295 if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
1296 if (!ctx.F.isZero(cond.value[0])) {
1297 return gen(ctx, ast.values[1]);
1298 } else {
1299 return gen(ctx, ast.values[2]);
1300 }
1301 }
1302}
1303
1304function genInclude(ctx, ast) {
1305 return ast.block ? gen(ctx, ast.block) : "";
1306}
1307
1308