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