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