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