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