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