arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/c_gen.js
src/c_gen.jsRaw
  1const bigInt = require("big-integer");
  2const utils = require("./utils");
  3
  4module.exports =  gen;
  5
  6
  7function newRef(ctx, type, _name, value, _sizes) {
  8    const isValue = ((typeof(value) != "undefined")&&(value != null));
  9    let name;
 10    let sizes;
 11    if (!_name) {
 12        name = ctx.getTmpName();
 13    } else {
 14        if (_name[0] =="_") {
 15            name = ctx.getTmpName(_name);
 16        } else {
 17            name = _name;
 18        }
 19    }
 20    if (typeof(_sizes) == "string") {
 21        sizes = _sizes;
 22    } else if (Array.isArray(_sizes)) {
 23        sizes = newSizes(ctx, _sizes);
 24    } else if (isValue) {
 25        sizes = newSizes(ctx, utils.extractSizes(value));
 26    } else {
 27        sizes = newSizes(ctx, []);
 28    }
 29
 30    const scope = ctx.scopes[ctx.scopes.length-1];
 31    if (scope[name]) return error("Variable already exists: " + name);
 32
 33    const label = scope._prefix + name;
 34    scope[name] = {
 35        stack: true,
 36        type: type,
 37        used: false,
 38        sizes: sizes,
 39        label: label
 40    };
 41
 42    if (isValue) {
 43        scope[name].value = value;
 44    }
 45
 46    return name;
 47}
 48
 49function newSizes(ctx, sizes) {
 50    const scope = ctx.scopes[ctx.scopes.length-1];
 51
 52    const name = ctx.getTmpName("_sz");
 53
 54    scope[name] = {
 55        stack: true,
 56        type: "SIZES",
 57        used: false,
 58        dim: sizes.length,
 59        label: name,
 60        value: sizes
 61    };
 62
 63    return name;
 64}
 65
 66
 67function instantiateRef(ctx, name) {
 68    const v = getScope(ctx, name);
 69    if (!v.stack) return error("Using a non existing var: " + name);
 70    if (v.used) return;
 71
 72    if (v.type=="BIGINT") {
 73
 74        const iSize = getScope(ctx, v.sizes);
 75
 76        if (iSize.used) {
 77            const labelSize = iSize.label;
 78            ctx.codeHeader += `PBigInt ${v.label};\n`;
 79            ctx.code += `${v.label} = ctx->allocBigInts(${labelSize});\n`;
 80            ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`;
 81        } else if (iSize.value) {
 82            const labelSize = ctx.addSizes(iSize.value);
 83            ctx.codeHeader += `PBigInt ${v.label} = ctx->allocBigInts(${labelSize});\n`;
 84            ctx.codeFooter += `ctx->freeBigInts(${v.label}, ${labelSize});\n`;
 85        } else {
 86            return error(ctx, null, "Undefined Sizes: " +name);
 87        }
 88
 89    } else if (v.type=="INT") {
 90        ctx.codeHeader += `int ${v.label};\n`;
 91    } else if (v.type=="SIZES") {
 92        ctx.codeHeader += `Circom_Sizes ${v.label};\n`;
 93    }
 94    v.used = true;
 95}
 96
 97
 98function error(ctx, ast, errStr) {
 99    ctx.error = {
100        pos:   {
101            first_line: ast.first_line,
102            first_column: ast.first_column,
103            last_line: ast.last_line,
104            last_column: ast.last_column
105        },
106        errStr: errStr,
107        ast: ast,
108        message: errStr
109    };
110}
111
112
113function getScope(ctx, name) {
114    for (let i=ctx.scopes.length-1; i>=0; i--) {
115        if (ctx.scopes[i][name]) return ctx.scopes[i][name];
116    }
117    return null;
118}
119
120
121
122function gen(ctx, ast) {
123    if ((ast.type == "NUMBER") ) {
124        return genNumber(ctx, ast);
125    } else if (ast.type == "VARIABLE") {
126        return genVariable(ctx, ast);
127    } else if (ast.type == "PIN") {
128        return genPin(ctx, ast);
129    } else if (ast.type == "OP") {
130        if (ast.op == "=") {
131            return genVarAssignement(ctx, ast);
132        } else if (ast.op == "<--") {
133            return genVarAssignement(ctx, ast);
134        } else if (ast.op == "<==") {
135            return genSignalAssignConstrain(ctx, ast);
136        } else if (ast.op == "===") {
137            return genConstraint(ctx, ast);
138        } else if (ast.op == "+=") {
139            return genVarAddAssignement(ctx, ast);
140        } else if (ast.op == "*=") {
141            return genVarMulAssignement(ctx, ast);
142        } else if (ast.op == "+") {
143            return genAdd(ctx, ast);
144        } else if (ast.op == "-") {
145            return genSub(ctx, ast);
146        } else if (ast.op == "UMINUS") {
147            return genUMinus(ctx, ast);
148        } else if (ast.op == "*") {
149            return genMul(ctx, ast);
150        } else if (ast.op == "%") {
151            return genMod(ctx, ast);
152        } else if (ast.op == "PLUSPLUSRIGHT") {
153            return genPlusPlusRight(ctx, ast);
154        } else if (ast.op == "PLUSPLUSLEFT") {
155            return genPlusPlusLeft(ctx, ast);
156        } else if (ast.op == "MINUSMINUSRIGHT") {
157            return genMinusMinusRight(ctx, ast);
158        } else if (ast.op == "MINUSMINUSLEFT") {
159            return genMinusMinusLeft(ctx, ast);
160        } else if (ast.op == "**") {
161            return genExp(ctx, ast);
162        } else if (ast.op == "/") {
163            return genDiv(ctx, ast);
164        } else if (ast.op == "\\") {
165            return genIDiv(ctx, ast);
166        } else if (ast.op == "&") {
167            return genBAnd(ctx, ast);
168        } else if (ast.op == "&&") {
169            return genAnd(ctx, ast);
170        } else if (ast.op == "||") {
171            return genOr(ctx, ast);
172        } else if (ast.op == "<<") {
173            return genShl(ctx, ast);
174        } else if (ast.op == ">>") {
175            return genShr(ctx, ast);
176        } else if (ast.op == "<") {
177            return genLt(ctx, ast);
178        } else if (ast.op == ">") {
179            return genGt(ctx, ast);
180        } else if (ast.op == "<=") {
181            return genLte(ctx, ast);
182        } else if (ast.op == ">=") {
183            return genGte(ctx, ast);
184        } else if (ast.op == "==") {
185            return genEq(ctx, ast);
186        } else if (ast.op == "!=") {
187            return genNeq(ctx, ast);
188        } else if (ast.op == "?") {
189            return genTerCon(ctx, ast);
190        } else {
191            error(ctx, ast, "Invalid operation: " + ast.op);
192        }
193    } else if (ast.type == "DECLARE") {
194        if (ast.declareType == "COMPONENT") {
195            return genDeclareComponent(ctx, ast);
196        } else if ((ast.declareType == "SIGNALIN")||
197                   (ast.declareType == "SIGNALOUT")||
198                   (ast.declareType == "SIGNAL")) {
199            return genDeclareSignal(ctx, ast);
200        } else if (ast.declareType == "VARIABLE") {
201            return genDeclareVariable(ctx, ast);
202        } else {
203            error(ctx, ast, "Invalid declaration: " + ast.declareType);
204        }
205    } else if (ast.type == "FUNCTIONCALL") {
206        return genFunctionCall(ctx, ast);
207    } else if (ast.type == "BLOCK") {
208        return genBlock(ctx, ast);
209    } else if (ast.type == "COMPUTE") {
210        return genCompute(ctx, ast);
211    } else if (ast.type == "FOR") {
212        return genFor(ctx, ast);
213    } else if (ast.type == "WHILE") {
214        return genWhile(ctx, ast);
215    } else if (ast.type == "IF") {
216        return genIf(ctx, ast);
217    } else if (ast.type == "RETURN") {
218        return genReturn(ctx, ast);
219    } else if (ast.type == "INCLUDE") {
220        return genInclude(ctx, ast);
221    } else if (ast.type == "ARRAY") {
222        return genArray(ctx, ast);
223    } else {
224        error(ctx, ast, "GEN -> Invalid AST node type: " + ast.type);
225    }
226}
227
228function genBlock(ctx, ast) {
229    const oldCode = ctx.code;
230    let res = null;
231    ctx.code = "";
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    if (ctx.scopes.length>1) {
240        ctx.code = oldCode + `{\n${utils.ident(ctx.code)}}\n`;
241    } else {
242        ctx.code = oldCode + ctx.code;
243    }
244    return res;
245}
246
247function genSrcComment(ctx, ast) {
248    let codes = [];
249    const fl= ast.first_line-1;
250    const ll = ast.last_line-1;
251    const fc = ast.first_column-1;
252    const lc = ast.last_column;
253    for (let i=fl; i<=ll; i++) {
254        const p1 = i==fl ? fc : 0;
255        const p2 = i==ll ? lc : -1;
256        codes.push(ctx.includedFiles[ctx.fileName][i].slice(p1, p2>=0 ? p2 : undefined));
257    }
258    ctx.code += "\n/* "+codes.join("\n")+"*/\n";
259}
260
261
262function genDeclareComponent(ctx, ast) {
263    const scope = ctx.scopes[ctx.scopes.length - 1];
264
265    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
266    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
267
268    scope[ast.name.name] = {
269        type: "COMPONENT",
270        label: ast.name.name
271    };
272
273    return ast.name.name;
274}
275
276function genDeclareSignal(ctx, ast) {
277    const scope = ctx.scopes[ctx.scopes.length-1];
278
279    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
280    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
281
282    const res = {
283        type: "SIGNAL",
284        label: ast.name.name
285    };
286
287    scope[ast.name.name] = res;
288
289    return res;
290}
291
292function genDeclareVariable(ctx, ast) {
293
294    const scope = ctx.scopes[ctx.scopes.length-1];
295
296    const varName = ast.name.name;
297    const labelName = scope._prefix + ast.name.name;
298
299    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
300    if (ctx.scope[varName]) return error(ctx, ast, "Name already exists: "+varName);
301
302    const sizes=[];
303    let instantiate = false;
304    for (let i=0; i< ast.name.selectors.length; i++) {
305        const size = gen(ctx, ast.name.selectors[i]);
306        if (ctx.error) return;
307
308        if (size.used) {
309            instantiate = true;
310            sizes.push(`BigInt2Int(${scope[size].label})`);
311        } else {
312            sizes.push(size.value.toJSNumber());
313        }
314
315        sizes.push( size.value.toJSNumber() );
316    }
317
318    const vSizes = newRef(ctx, "SIZES", "_sizes");
319    const iSizes = scope[vSizes];
320    iSizes.dim = ast.name.selectors.length;
321    if (instantiate) {
322        instantiateRef(ctx, vSizes);
323        ctx.code += `${iSizes.label}[${iSizes.dim+1}]=0`;
324        ctx.code += `${iSizes.label}[${iSizes.dim}]=1`;
325        for (let i=iSizes.dim-1; i>=0; i--) {
326            ctx.code += `${iSizes.label}[${i}] = ${sizes[i]}*${iSizes.label}[${i+1}];\n`;
327        }
328    } else {
329        iSizes.value = sizes;
330    }
331
332    const res = ctx.scope[varName] = {
333        stack: true,
334        type: "BIGINT",
335        sizes: vSizes,
336        label: labelName
337    };
338
339    scope[varName] = res;
340
341    return res;
342}
343
344function genNumber(ctx, ast) {
345    return newRef(ctx, "BIGINT", "_num", ast.value);
346}
347
348
349
350function genGetOffset(ctx, vOffset, vSizes, sels) {
351
352    let rN = 0;
353    let rStr = "";
354    let iOffset;
355
356    if (vOffset) {
357        iOffset = getScope(ctx, vOffset);
358        if (iOffset.used) {
359            rStr += iOffset.label;
360        } else {
361            rN += iOffset.value.toJSNumber();
362        }
363    }
364
365    if ((sels)&&(sels.length>0)) {
366
367        const iSizes = getScope(ctx, vSizes);
368
369        for (let i=0; i<sels.length; i++) {
370            const vIdx = gen(ctx, sels[i]);
371            const iIdx = getScope(ctx, vIdx);
372
373            if ((!iIdx.used) && (!iSizes.used)) {
374                rN = rN + iIdx.value * iSizes.sizes[i+1];
375            } else {
376                if (rN>0) {
377                    if (rStr != "") rStr += " + ";
378                    rStr += rN;
379                    rN =0;
380                }
381
382                if (rStr != "") rStr += " + ";
383                if (iIdx.used) {
384                    rStr += vIdx;
385                } else {
386                    rStr += iIdx.value;
387                }
388                rStr += "*";
389                if (iSizes.used) {
390                    rStr += `${iSizes.label}[${i+1}]`;
391                } else {
392                    rStr += iSizes.sizes[i+1];
393                }
394            }
395        }
396    }
397
398    if (rStr == "") {
399        const o = newRef(ctx, "INT", "_offset", rN);
400        return o;
401    } else {
402        if (rN>0) {
403            if (rStr != "") rStr += " + ";
404            rStr += rN;
405            rN =0;
406        }
407        if (rStr == iOffset.label) {
408            return vOffset;
409        } else {
410            const res = newRef(ctx, "INT", "_offset");
411            instantiateRef(ctx, res);
412            ctx.code += `${res} = ${rStr};\n`;
413            return res;
414        }
415    }
416}
417
418function genVariable(ctx, ast) {
419    const v = getScope(ctx, ast.name);
420
421
422    if (v.type == "SIGNAL") {
423        let vOffset;
424        if (ast.selectors.length>0) {
425            const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name);
426            const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", ast.name);
427            vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
428        } else {
429            vOffset = genGetSigalOffset(ctx, "ctx->cIdx", ast.name);
430        }
431        return genGetSignal(ctx, "ctx->cIdx", vOffset);
432
433    } else if (v.type == "BIGINT") {
434        const vOffset = genGetOffset(ctx, 0, v.sizes, ast.sels );
435        if (v.used) {
436            if (vOffset == 0) {
437                return ast.name;
438            } else {
439                const res = newRef(ctx, "BIGINT", "_v");
440                instantiateRef(ctx, res);
441                ctx.code += `${res} = ${ast.name} + ${vOffset};\n`;
442                return res;
443            }
444        } else {
445            if (typeof(vOffset) == "string") {
446                instantiateRef(ctx, ast.name);
447                const vConstant = instantiateConstant(ctx, v.value);
448                const res = newRef(ctx, "BIGINT", "_v");
449                instantiateRef(ctx, res);
450                ctx.code += `${res} = ${vConstant} + ${vOffset};\n`;
451                return res;
452            } else {
453                const sa = utils.subArray(v.value, ast.selectors);
454                const res = newRef(ctx, "BIGINT", "_v", sa);
455                return res;
456            }
457        }
458    }
459
460    const sels = [];
461    for (let i=0; i<ast.selectors.length; i++) {
462        sels.push(gen(ctx, ast.selectors[i]));
463        if (ctx.error) return;
464    }
465
466    if (!v) {
467        return error(ctx, ast, "Invalid left operand");
468    }
469    if (v.type == "VARIABLE") {
470        return `ctx.getVar("${ast.name}",[${sels.join(",")}])`;
471    } else if (v.type == "SIGNAL") {
472        return `ctx.getSignal("${ast.name}", [${sels.join(",")}])`;
473    } else {
474        error(ctx, ast, "Invalid Variable type");
475    }
476}
477
478function instantiateConstant(ctx, value) {
479    const flatedValue = utils.flatArray(value);
480    const res = ctx.getTmpName("_const");
481    ctx.codeHeader += `PBigInt ${res};\n`;
482    ctx.code += `${res.label} = ctx->allocBigInts(${flatedValue.length});\n`;
483    for (let i=0; i<flatedValue.length; i++) {
484        ctx.code += `mpz_init_set_str(${res.label}[${i}], ${flatedValue[i].toString(16)}, 16);\n`;
485    }
486    ctx.codeFooter += `ctx->freeBigInts(${res.label});\n`;
487    return res;
488}
489
490function genPin(ctx, ast) {
491    let vcIdx;
492    if (ast.component.selectors.length>0) {
493        const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name);
494        const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.component.name);
495        vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors );
496    } else {
497        vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.component.name);
498    }
499
500    let vsIdx;
501    if (ast.pin.selectors.length>0) {
502        const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
503        const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name);
504        vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors );
505    } else {
506        vsIdx = genGetSigalOffset(ctx, vcIdx, ast.pin.name);
507    }
508
509    return genGetSignal(ctx, vcIdx, vsIdx);
510}
511
512function genGetSubComponentOffset(ctx, cIdx, label) {
513    const vOffset = newRef(ctx, "INT", "_compIdx");
514    instantiateRef(ctx, vOffset);
515
516    const h = utils.fnvHash(label);
517    ctx.code += `${vOffset} = ctx->getSubComponentOffset(${cIdx}, 0x${h}LL /* ${label} */);\n`;
518    return vOffset;
519}
520
521function genGetSubComponentSizes(ctx, cIdx, label) {
522    const vSizes = newRef(ctx, "SIZES", "_compSizes");
523    instantiateRef(ctx, vSizes);
524
525    const h = utils.fnvHash(label);
526    ctx.code += `${vSizes} = ctx->getSubComponentSizes(${cIdx}, 0x${h}LL /* ${label} */);\n`;
527    return vSizes;
528}
529
530function genGetSigalOffset(ctx, sIdx, label) {
531    const vOffset = newRef(ctx, "INT", "_sigIdx");
532    instantiateRef(ctx, vOffset);
533
534    const h = utils.fnvHash(label);
535    ctx.code += `${vOffset} = ctx->getSignalOffset(${sIdx}, 0x${h}LL /* ${label} */);\n`;
536    return vOffset;
537}
538
539function genGetSignalSizes(ctx, sIdx, label) {
540    const vSizes = newRef(ctx, "SIZES", "_sigSizes");
541    instantiateRef(ctx, vSizes);
542
543    const h = utils.fnvHash(label);
544    ctx.code += `${vSizes} = ctx->getSignalSizes(${sIdx}, 0x${h}LL /* ${label} */);\n`;
545    return vSizes;
546}
547
548function genSetSignal(ctx, cIdx, sIdx, value) {
549    ctx.code += `ctx->setSignal(${cIdx}, ${sIdx}, ${value});\n`;
550    return value;
551}
552
553function genGetSignal(ctx, cIdx, sIdx) {
554    const res = newRef(ctx, "BIGINT", "_sigValue");
555    instantiateRef(ctx, res);
556    ctx.code += `ctx->getSignal(${cIdx}, ${sIdx}, ${res});\n`;
557    return res;
558}
559
560function genVarAssignement(ctx, ast) {
561
562    let lName;
563    let sels;
564
565    if (ctx.error) return;
566
567    if (ast.values[0].type == "PIN") {
568
569        let vcIdx;
570        if (ast.values[0].component.selectors.length>0) {
571            const vcOffset = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name);
572            const vcSizes = genGetSubComponentSizes(ctx, "ctx->cIdx", ast.values[0].component.name);
573            vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors );
574        } else {
575            vcIdx = genGetSubComponentOffset(ctx, "ctx->cIdx", ast.values[0].component.name);
576        }
577
578        let vsIdx;
579        if (ast.values[0].pin.selectors.length>0) {
580            const vsOffset = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
581            const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name);
582            vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors );
583        } else {
584            vsIdx = genGetSigalOffset(ctx, vcIdx, ast.values[0].pin.name);
585        }
586
587        const vVal = gen(ctx, ast.values[1]);
588
589        genSetSignal(ctx, vcIdx, vsIdx, vVal);
590
591        return vVal;
592    }
593
594    if (ast.values[0].type == "DECLARE") {
595        lName = gen(ctx, ast.values[0]);
596        if (ctx.error) return;
597        sels = [];
598    } else {
599        lName = ast.values[0].name;
600        sels = ast.values[0].selectors;
601    }
602
603
604    const left = getScope(ctx, lName);
605    if (!left) return error(ctx, ast, "Variable does not exists: "+ast.values[0].name);
606
607    // Component instantiation is already done.
608    if (left.type == "COMPONENT") {
609        ctx.last = lName;
610        return;
611    }
612
613
614    const rName = gen(ctx, ast.values[1]);
615    const right = getScope(ctx, rName);
616
617    if (left.type == "SIGNAL") {
618
619        let vsIdx;
620        if (sels.length>0) {
621            const vsOffset = genGetSigalOffset(ctx, "ctx->cIdx", lName);
622            const vsSizes = genGetSignalSizes(ctx, "ctx->cIdx", lName);
623            vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels );
624        } else {
625            vsIdx = genGetSigalOffset(ctx, "ctx->cIdx", lName);
626        }
627
628        return genSetSignal(ctx, "ctx->cIdx", vsIdx, rName);
629    } else if (left.type == "VAR") {
630        if (left.used) {
631            if (!right.used) {
632                instantiateRef(ctx, rName);
633            }
634            ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`;
635            return lName;
636        } else {
637            if (right.used) {
638                instantiateRef(ctx, lName);
639                ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`;
640                return lName;
641            } else {
642                if (!left.value) {
643                    left.value = right.value;
644                } else {
645                    if (!left.value.equals(right.value)) {
646                        if (ctx.scopes.length > 1) {
647                            instantiateRef(ctx, lName);
648                            ctx.code += `BigInt_copy(${left.label}, ${right.label});\n`;
649                        } else {
650                            left.value = right.value;
651                        }
652                    }
653                }
654            }
655        }
656    } else {
657        return error(ctx, ast, "Assigning to invalid");
658    }
659}
660
661function genConstraint(ctx, ast) {
662    const a = gen(ctx, ast.values[0]);
663    if (ctx.error) return;
664    const b = gen(ctx, ast.values[1]);
665    if (ctx.error) return;
666    const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
667    ctx.code += `ctx->checkConstraint(${a}, ${b}, "${strErr}");`;
668}
669
670
671function genArray(ctx, ast) {
672    let S = "[";
673    for (let i=0; i<ast.values.length; i++) {
674        if (i>0) S += ",";
675        S += gen(ctx, ast.values[i]);
676    }
677    S+="]";
678    return S;
679}
680
681
682function genFunctionCall(ctx, ast) {
683    let S = "[";
684    for (let i=0; i<ast.params.length; i++) {
685        if (i>0) S += ",";
686        S += gen(ctx, ast.params[i]);
687    }
688    S+="]";
689
690    return `ctx.callFunction("${ast.name}", ${S})`;
691}
692
693function genFor(ctx, ast) {
694    ctx.scopes.push({});
695    const init = gen(ctx, ast.init);
696    if (ctx.error) return;
697    const condition = gen(ctx, ast.condition);
698    if (ctx.error) return;
699    const step = gen(ctx, ast.step);
700    if (ctx.error) return;
701    const body = gen(ctx, ast.body);
702    if (ctx.error) return;
703    ctx.scopes.pop();
704    return `for (${init};bigInt(${condition}).neq(bigInt(0));${step}) { \n${body}\n }\n`;
705}
706
707function genWhile(ctx, ast) {
708    const condition = gen(ctx, ast.condition);
709    if (ctx.error) return;
710    const body = gen(ctx, ast.body);
711    if (ctx.error) return;
712    return `while (bigInt(${condition}).neq(bigInt(0))) {\n${body}\n}\n`;
713}
714
715function genCompute(ctx, ast) {
716    const body = gen(ctx, ast.body);
717    if (ctx.error) return;
718    return `{\n${body}\n}\n`;
719}
720
721function genIf(ctx, ast) {
722    const condition = gen(ctx, ast.condition);
723    if (ctx.error) return;
724    const thenBody = gen(ctx, ast.then);
725    if (ctx.error) return;
726    if (ast.else) {
727        const elseBody = gen(ctx, ast.else);
728        if (ctx.error) return;
729        return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n} else {\n${elseBody}\n}\n`;
730    } else {
731        return `if (bigInt(${condition}).neq(bigInt(0))) {\n${thenBody}\n}\n`;
732    }
733}
734
735
736function genReturn(ctx, ast) {
737    const value = gen(ctx, ast.value);
738    if (ctx.error) return;
739    return `return ${value};`;
740}
741
742
743
744function genSignalAssignConstrain(ctx, ast) {
745    const res = genVarAssignement(ctx, ast);
746    genConstraint(ctx, ast);
747    return res;
748//    return genVarAssignement(ctx, ast);
749}
750
751function genVarAddAssignement(ctx, ast) {
752    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
753}
754
755function genVarMulAssignement(ctx, ast) {
756    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
757}
758
759function genPlusPlusRight(ctx, ast) {
760    return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`;
761}
762
763function genPlusPlusLeft(ctx, ast) {
764    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]});
765}
766
767function genMinusMinusRight(ctx, ast) {
768    return `(${genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]})}).add(__P__).sub(bigInt(1)).mod(__P__)`;
769}
770
771function genMinusMinusLeft(ctx, ast) {
772    return genVarAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "-", values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}]}]});
773}
774
775function genAdd(ctx, ast) {
776    const a = gen(ctx, ast.values[0]);
777    if (ctx.error) return;
778    const b = gen(ctx, ast.values[1]);
779    if (ctx.error) return;
780    return `bigInt(${a}).add(bigInt(${b})).mod(__P__)`;
781}
782
783function genMul(ctx, ast) {
784    const a = gen(ctx, ast.values[0]);
785    if (ctx.error) return;
786    const b = gen(ctx, ast.values[1]);
787    if (ctx.error) return;
788    return `bigInt(${a}).mul(bigInt(${b})).mod(__P__)`;
789}
790
791function genSub(ctx, ast) {
792    const a = gen(ctx, ast.values[0]);
793    if (ctx.error) return;
794    const b = gen(ctx, ast.values[1]);
795    if (ctx.error) return;
796    return `bigInt(${a}).add(__P__).sub(bigInt(${b})).mod(__P__)`;
797}
798
799function genDiv(ctx, ast) {
800    const a = gen(ctx, ast.values[0]);
801    if (ctx.error) return;
802    const b = gen(ctx, ast.values[1]);
803    if (ctx.error) return;
804
805    return `bigInt(${a}).mul( bigInt(${b}).inverse(__P__) ).mod(__P__)`;
806}
807
808function genIDiv(ctx, ast) {
809    const a = gen(ctx, ast.values[0]);
810    if (ctx.error) return;
811    const b = gen(ctx, ast.values[1]);
812    if (ctx.error) return;
813
814    return `bigInt(${a}).div( bigInt(${b}))`;
815}
816
817function genExp(ctx, ast) {
818    const a = gen(ctx, ast.values[0]);
819    if (ctx.error) return;
820    const b = gen(ctx, ast.values[1]);
821    if (ctx.error) return;
822    return `bigInt(${a}).modPow(bigInt(${b}), __P__)`;
823}
824
825function genBAnd(ctx, ast) {
826    const a = gen(ctx, ast.values[0]);
827    if (ctx.error) return;
828    const b = gen(ctx, ast.values[1]);
829    if (ctx.error) return;
830    return `bigInt(${a}).and(bigInt(${b})).and(__MASK__)`;
831}
832
833function genAnd(ctx, ast) {
834    const a = gen(ctx, ast.values[0]);
835    if (ctx.error) return;
836    const b = gen(ctx, ast.values[1]);
837    if (ctx.error) return;
838    return `((bigInt(${a}).neq(bigInt(0)) && bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
839}
840
841function genOr(ctx, ast) {
842    const a = gen(ctx, ast.values[0]);
843    if (ctx.error) return;
844    const b = gen(ctx, ast.values[1]);
845    if (ctx.error) return;
846    return `((bigInt(${a}).neq(bigInt(0)) || bigInt(${b}).neq(bigInt(0))) ? bigInt(1) : bigInt(0))`;
847}
848
849function genShl(ctx, ast) {
850    const a = gen(ctx, ast.values[0]);
851    if (ctx.error) return;
852    const b = gen(ctx, ast.values[1]);
853    if (ctx.error) return;
854    return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shl(bigInt(${b})).and(__MASK__)`;
855}
856
857function genShr(ctx, ast) {
858    const a = gen(ctx, ast.values[0]);
859    if (ctx.error) return;
860    const b = gen(ctx, ast.values[1]);
861    if (ctx.error) return;
862    return `bigInt(${b}).greater(bigInt(256)) ? 0 : bigInt(${a}).shr(bigInt(${b})).and(__MASK__)`;
863}
864
865function genMod(ctx, ast) {
866    const a = gen(ctx, ast.values[0]);
867    if (ctx.error) return;
868    const b = gen(ctx, ast.values[1]);
869    if (ctx.error) return;
870    return `bigInt(${a}).mod(bigInt(${b}))`;
871}
872
873function genLt(ctx, ast) {
874    const a = gen(ctx, ast.values[0]);
875    if (ctx.error) return;
876    const b = gen(ctx, ast.values[1]);
877    if (ctx.error) return;
878    return `bigInt(${a}).lt(bigInt(${b})) ? 1 : 0`;
879}
880
881function genGt(ctx, ast) {
882    const a = gen(ctx, ast.values[0]);
883    if (ctx.error) return;
884    const b = gen(ctx, ast.values[1]);
885    if (ctx.error) return;
886    return `bigInt(${a}).gt(bigInt(${b})) ? 1 : 0`;
887}
888
889function genLte(ctx, ast) {
890    const a = gen(ctx, ast.values[0]);
891    if (ctx.error) return;
892    const b = gen(ctx, ast.values[1]);
893    if (ctx.error) return;
894    return `bigInt(${a}).lesserOrEquals(bigInt(${b})) ? 1 : 0`;
895}
896
897function genGte(ctx, ast) {
898    const a = gen(ctx, ast.values[0]);
899    if (ctx.error) return;
900    const b = gen(ctx, ast.values[1]);
901    if (ctx.error) return;
902    return `bigInt(${a}).greaterOrEquals(bigInt(${b})) ? 1 : 0`;
903}
904
905function genEq(ctx, ast) {
906    const a = gen(ctx, ast.values[0]);
907    if (ctx.error) return;
908    const b = gen(ctx, ast.values[1]);
909    if (ctx.error) return;
910    return `(bigInt(${a}).eq(bigInt(${b})) ? 1 : 0)`;
911}
912
913function genNeq(ctx, ast) {
914    const a = gen(ctx, ast.values[0]);
915    if (ctx.error) return;
916    const b = gen(ctx, ast.values[1]);
917    if (ctx.error) return;
918    return `(bigInt(${a}).eq(bigInt(${b})) ? 0 : 1)`;
919}
920
921function genUMinus(ctx, ast) {
922    const a = gen(ctx, ast.values[0]);
923    if (ctx.error) return;
924    return `__P__.sub(bigInt(${a})).mod(__P__)`;
925}
926
927function genTerCon(ctx, ast) {
928    const a = gen(ctx, ast.values[0]);
929    if (ctx.error) return;
930    const b = gen(ctx, ast.values[1]);
931    if (ctx.error) return;
932    const c = gen(ctx, ast.values[2]);
933    if (ctx.error) return;
934    return `bigInt(${a}).neq(bigInt(0)) ? (${b}) : (${c})`;
935}
936
937function genInclude(ctx, ast) {
938    return ast.block ? gen(ctx, ast.block) : "";
939}
940
941