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    return ast.refId;
 288}
 289
 290function genDeclareVariable(ctx, ast) {
 291
 292
 293    const v = ctx.refs[ast.refId];
 294
 295    let sizes;
 296    if (ast.name.selectors.length>0) {
 297        sizes=[];
 298        for (let i=0; i< ast.name.selectors.length; i++) {
 299            const sizeRef = gen(ctx, ast.name.selectors[i]);
 300            const size = ctx.refs[sizeRef];
 301            if (size.sizes[0] != 1) return ctx.throwError(ast, "A selector cannot be an array");
 302            if (size.used) return ctx.throwError(ast, "Variable size variables not allowed");
 303            sizes.push(Scalar.toNumber(size.value[0]));
 304        }
 305        sizes = utils.accSizes(sizes);
 306    } else {
 307        sizes = [1,0];
 308    }
 309
 310    if ((!v.sizes)&&(sizes)) {
 311        v.sizes = sizes;
 312        v.value = new Array(sizes[0]);
 313    }
 314
 315    if (v.sizes) {
 316        if (!utils.sameSizes(v.sizes, sizes)) return ctx.throwError(ast, "Redefined a var with different sized");
 317    }
 318
 319    return ast.refId;
 320}
 321
 322function genNumber(ctx, ast) {
 323    return newRef(ctx, "BIGINT", "_num", ctx.F.e(ast.value));
 324}
 325
 326
 327
 328function genGetOffset(ctx, refOffset, vSizes, sels) {
 329
 330    let offsets = [];
 331    let offset;
 332
 333    let isConstant = true;
 334    let constant = 0;
 335    let isRef = false;
 336
 337    if (refOffset) {
 338        offset = ctx.refs[refOffset];
 339        if (offset.used) {
 340            offsets.push([["RI", offset.label], ["V", 1]]);
 341            isRef = true;
 342            isConstant = false;
 343        } else {
 344            offsets.push([["V", parseInt(offset.value)], ["V", 1]]);
 345            constant =  parseInt(offset.value);
 346        }
 347    }
 348
 349    if ((sels)&&(sels.length>0)) {
 350
 351        let iSizes;
 352        if (Array.isArray(vSizes)) {
 353            iSizes = {
 354                used: false,
 355                sizes: vSizes
 356            };
 357        } else {
 358            iSizes = ctx.refs[vSizes];
 359        }
 360
 361        for (let i=0; i<sels.length; i++) {
 362            let idx, sze;
 363            const idxRef = gen(ctx, sels[i]);
 364            const iIdx = ctx.refs[idxRef];
 365            if (iIdx.used) {
 366                idx = ["R", iIdx.label];
 367            } else {
 368                idx = ["V", parseInt(iIdx.value[0])];
 369            }
 370            if (iSizes.used) {
 371                sze = ["RS", iSizes.label, i+1 ];
 372            } else {
 373                sze = ["V", iSizes.sizes[i+1] ];
 374            }
 375            offsets.push([idx, sze]);
 376            if ((idx[0] == "V")&&(sze[0] == "V")&&(isConstant)) {
 377                constant += idx[1]*sze[1];
 378                if (idx[1]*sze[1] > 0) isRef = false;
 379            } else {
 380                isConstant = false;
 381                isRef = false;
 382            }
 383        }
 384    }
 385
 386    if (isConstant) {
 387        const o = newRef(ctx, "INT", "_offset", constant);
 388        return o;
 389    }
 390    if (isRef) {
 391        return refOffset;
 392    }
 393    const resRef = newRef(ctx, "INT", "_offset");
 394    instantiateRef(ctx, resRef);
 395
 396    const res = ctx.refs[resRef];
 397
 398    ctx.codeBuilder.calcOffset(res.label, offsets);
 399    return resRef;
 400}
 401
 402function genVariable(ctx, ast) {
 403    const v = ctx.refs[ast.refId];
 404
 405    const l = ast.selectors ? ast.selectors.length : 0;
 406
 407    if (v.type == "SIGNAL") {
 408        let vOffset;
 409        if (l>0) {
 410            const vsOffset = genGetSignalOffset(ctx, -1, ast.name);
 411            const vsSizes = genGetSignalSizes(ctx, -1, ast.name);
 412            vOffset = genGetOffset(ctx, vsOffset, vsSizes, ast.selectors );
 413        } else {
 414            vOffset = genGetSignalOffset(ctx, -1, ast.name);
 415        }
 416
 417        const resRef = newRef(ctx, "BIGINT", "_sigValue");
 418        const res = ctx.refs[resRef];
 419        instantiateRef(ctx, resRef);
 420        ctx.codeBuilder.getSignal(res.label, ["CC"], toRefA_Int1(ctx, ast, vOffset));
 421        return resRef;
 422
 423    } else if (v.type == "BIGINT") {
 424        const refOffset = genGetOffset(ctx, 0, v.sizes, ast.selectors );
 425        const offset = ctx.refs[refOffset];
 426        let ot;
 427        if (offset.type == "BIGINT") {
 428            ot = "R";
 429        } else if (offset.type == "INT") {
 430            ot= "RI";
 431        } else {
 432            assert(false);
 433        }
 434        if (v.used) {
 435            if (offset.used) {
 436                const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
 437                const res = ctx.refs[refRes];
 438                res.used = true;
 439                ctx.fnBuilder.definePFrElement(res.label);
 440                ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
 441                return refRes;
 442            } else if ((offset.value[0]>0)||(l>0)) {
 443                const refRes = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
 444                const res = ctx.refs[refRes];
 445                res.used = true;
 446                ctx.fnBuilder.definePFrElement(res.label);
 447                ctx.codeBuilder.assign(res.label, ["R", v.label], ["V", offset.value[0]]);
 448                return refRes;
 449            } else {
 450                return ast.refId;
 451            }
 452        } else {
 453            if (offset.used) {
 454                instantiateRef(ctx, ast.refId, v.value);
 455                const resRef = newRef(ctx, "BIGINT", "_v", null, v.sizes.slice(l));
 456                const res = ctx.refs[resRef];
 457                res.used = true;
 458                ctx.fnBuilder.definePFrElement(res.label);
 459                ctx.codeBuilder.assign(res.label, ["R", v.label], [ot, offset.label]);
 460                return resRef;
 461            } else {
 462                // return newSubRef(ctx, ast.name, ast.selectors);
 463                return newRef(ctx, "BIGINT", "_v", v.value.slice(offset.value[0], offset.value[0] + v.sizes[l]),v.sizes.slice(l));
 464            }
 465        }
 466    }
 467}
 468
 469
 470function genPin(ctx, ast) {
 471    let vcIdx;
 472    if (ast.component.selectors.length>0) {
 473        const vcOffset = genGetSubComponentOffset(ctx, -1, ast.component.name);
 474        const vcSizes = genGetSubComponentSizes(ctx, -1, ast.component.name);
 475        vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.component.selectors );
 476    } else {
 477        vcIdx = genGetSubComponentOffset(ctx, -1, ast.component.name);
 478    }
 479
 480    let vsIdx;
 481    if (ast.pin.selectors.length>0) {
 482        const vsOffset = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
 483        const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.pin.name);
 484        vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.pin.selectors );
 485    } else {
 486        vsIdx = genGetSignalOffset(ctx, vcIdx, ast.pin.name);
 487    }
 488
 489    const resRef = newRef(ctx, "BIGINT", "_sigValue");
 490    const res = ctx.refs[resRef];
 491    instantiateRef(ctx, resRef);
 492    ctx.codeBuilder.getSignal(
 493        res.label,
 494        toRefA_Int1(ctx, ast.component, vcIdx),
 495        toRefA_Int1(ctx, ast.pin, vsIdx)
 496    );
 497    return resRef;
 498}
 499
 500function genGetSubComponentOffset(ctx, cIdxRef, label) {
 501    const refOffset = newRef(ctx, "INT", "_compIdx");
 502    const offset = ctx.refs[refOffset];
 503    instantiateRef(ctx, refOffset);
 504
 505    const h = utils.fnvHash(label);
 506    let c;
 507    if (cIdxRef>=0) {
 508        const cIdx = ctx.refs[cIdxRef];
 509        if (cIdx.used) {
 510            if (cIdx.type == "BIGINT") {
 511                c = ["R", cIdx.label];
 512            } else if (cIdx.type == "INT") {
 513                c = ["RI", cIdx.label];
 514            } else {
 515                assert(false);
 516            }
 517        } else {
 518            c = ["V", cIdx.value[0]];
 519        }
 520    } else {
 521        c = ["CC"];
 522    }
 523    ctx.codeBuilder.getSubComponentOffset(offset.label, c, h, label);
 524    return refOffset;
 525}
 526
 527function genGetSubComponentSizes(ctx, cIdxRef, label) {
 528    const sizesRef = newRef(ctx, "SIZES", "_compSizes");
 529    const sizes = ctx.refs[sizesRef];
 530    instantiateRef(ctx, sizesRef);
 531
 532    const h = utils.fnvHash(label);
 533    let c;
 534    if (cIdxRef>=0) {
 535        const cIdx = ctx.refs[cIdxRef];
 536        if (cIdx.used) {
 537            if (cIdx.type == "BIGINT") {
 538                c = ["R", cIdx.label];
 539            } else if (cIdx.type == "INT") {
 540                c = ["RI", cIdx.label];
 541            } else {
 542                assert(false);
 543            }
 544        } else {
 545            c = ["V", cIdx.value[0]];
 546        }
 547    } else {
 548        c = ["CC"];
 549    }
 550    ctx.codeBuilder.getSubComponentSizes(sizes.label, c, h, label);
 551    return sizesRef;
 552}
 553
 554function genGetSignalOffset(ctx, cIdxRef, label) {
 555
 556    let constCIdx = null;
 557    if (cIdxRef>=0) {
 558        const cIdx = ctx.refs[cIdxRef];
 559        if (!cIdx.used) {
 560            constCIdx = cIdx.value.toString()+"_"+label;
 561        }
 562    } else {
 563        constCIdx = "_cIdx_"+label;
 564    }
 565    if (constCIdx && ctx.getSignalOffsetCache[constCIdx]) return ctx.getSignalOffsetCache[constCIdx];
 566
 567    const refOffset = newRef(ctx, "INT", "_" + label + "_sigIdx_");
 568    const offset = ctx.refs[refOffset];
 569    instantiateRef(ctx, refOffset);
 570
 571    const h = utils.fnvHash(label);
 572    let c;
 573    if (cIdxRef>=0) {
 574        const cIdx = ctx.refs[cIdxRef];
 575        if (cIdx.used) {
 576            if (cIdx.type == "BIGINT") {
 577                c = ["R", cIdx.label];
 578            } else if (cIdx.type == "INT") {
 579                c = ["RI", cIdx.label];
 580            } else {
 581                assert(false);
 582            }
 583        } else {
 584            c = ["V", cIdx.value[0]];
 585        }
 586    } else {
 587        c = ["CC"];
 588    }
 589    if (constCIdx) {
 590        ctx.fnBuilder.initializeSignalOffset(offset.label, c, h, label);
 591        ctx.getSignalOffsetCache[constCIdx] = refOffset;
 592    } else {
 593        ctx.codeBuilder.getSignalOffset(offset.label, c, h, label);
 594    }
 595    return refOffset;
 596}
 597
 598function genGetSignalSizes(ctx, cIdxRef, label) {
 599    let constCIdx = null;
 600    if (cIdxRef>=0) {
 601        const cIdx = ctx.refs[cIdxRef];
 602        if (utils.isDefined(cIdx.value)) {
 603            constCIdx = cIdx.value.toString()+"_"+label;
 604        }
 605    } else {
 606        constCIdx = "_cIdx_"+label;
 607    }
 608    if (constCIdx && ctx.getSignalSizesCache[constCIdx]) return ctx.getSignalSizesCache[constCIdx];
 609
 610
 611    const refSizes = newRef(ctx, "SIZES", "_sigSizes_"+label);
 612    const sizes = ctx.refs[refSizes];
 613    instantiateRef(ctx, refSizes);
 614
 615    let c;
 616    if (cIdxRef>=0) {
 617        const cIdx = ctx.refs[cIdxRef];
 618        if (cIdx.used) {
 619            if (cIdx.type == "BIGINT") {
 620                c = ["R", cIdx.label];
 621            } else if (cIdx.type == "INT") {
 622                c = ["RI", cIdx.label];
 623            } else {
 624                assert(false);
 625            }
 626        } else {
 627            c = ["V", cIdx.value[0]];
 628        }
 629    } else {
 630        c = ["CC"];
 631    }
 632    const h = utils.fnvHash(label);
 633    if (constCIdx) {
 634        ctx.fnBuilder.initializeSignalSizes(sizes.label, c, h, label);
 635        ctx.getSignalSizesCache[constCIdx] = refSizes;
 636    } else {
 637        ctx.codeBuilder.getSignalSizes(sizes.label, c, h, label);
 638    }
 639    return refSizes;
 640}
 641
 642function genPinAssignement(ctx, ast) {
 643    let vcIdx;
 644    if (ast.values[0].component.selectors.length>0) {
 645        const vcOffset = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
 646        const vcSizes = genGetSubComponentSizes(ctx, -1, ast.values[0].component.name);
 647        vcIdx = genGetOffset(ctx, vcOffset, vcSizes, ast.values[0].component.selectors );
 648    } else {
 649        vcIdx = genGetSubComponentOffset(ctx, -1, ast.values[0].component.name);
 650    }
 651
 652    let vsIdx;
 653    if (ast.values[0].pin.selectors.length>0) {
 654        const vsOffset = genGetSignalOffset(ctx, vcIdx, ast.values[0].pin.name);
 655        const vsSizes = genGetSignalSizes(ctx, vcIdx, ast.values[0].pin.name);
 656        vsIdx = genGetOffset(ctx, vsOffset, vsSizes, ast.values[0].pin.selectors );
 657    } else {
 658        vsIdx = genGetSignalOffset(ctx, vcIdx, ast.values[0].pin.name);
 659    }
 660
 661    const vVal = gen(ctx, ast.values[1]);
 662
 663    ctx.codeBuilder.setSignal(
 664        toRefA_Int1(ctx, ast.values[0].component, vcIdx),
 665        toRefA_Int1(ctx, ast.values[0].pin, vsIdx),
 666        toRefA_Fr1(ctx, ast.values[1], vVal)
 667    );
 668
 669    return vVal;
 670}
 671
 672function genSignalAssignmen(ctx, ast, lName, sels, rName) {
 673    let vsIdx;
 674    const signal = ctx.refs[lName];
 675    if (sels.length>0) {
 676        const vsOffset = genGetSignalOffset(ctx, -1, signal.label);
 677        const vsSizes = genGetSignalSizes(ctx, -1, signal.label);
 678        vsIdx = genGetOffset(ctx, vsOffset, vsSizes, sels );
 679    } else {
 680        vsIdx = genGetSignalOffset(ctx, -1, signal.label);
 681    }
 682
 683    ctx.codeBuilder.setSignal(
 684        ["CC"],
 685        toRefA_Int1(ctx, ast.values[0], vsIdx),
 686        toRefA_Fr1(ctx, ast.values[1], rName)
 687    );
 688}
 689
 690function genVarAssignment(ctx, ast, lRef, sels, rRef) {
 691
 692    const left = ctx.refs[lRef];
 693    const right = ctx.refs[rRef];
 694    if (!utils.isDefined(left.sizes)) {
 695        left.sizes = right.sizes;
 696        left.value = new Array(left.sizes[0]);
 697    }
 698    if (!utils.sameSizes(left.sizes.slice(sels.length), right.sizes)) return ctx.throwError(ast, "Sizes do not match");
 699
 700    const oRef = genGetOffset(ctx, 0, left.sizes, sels);
 701    const offset = ctx.refs[oRef];
 702
 703    let instantiated=false;
 704    if (left.used) {
 705        instantiateRef(ctx, rRef, right.value);
 706        instantiated=true;
 707    } else if (right.used) {
 708        if (sels.length == 0) {
 709            instantiateRef(ctx,lRef);
 710        } else {
 711            instantiateRef(ctx,lRef, left.value);
 712        }
 713        instantiated=true;
 714    } else if (offset.used) {
 715        instantiateRef(ctx, rRef, right.value);
 716        if (sels.length == 0) {
 717            instantiateRef(ctx,lRef);
 718        } else {
 719            instantiateRef(ctx,lRef, left.value);
 720        }
 721        instantiated=true;
 722    }
 723
 724    if (instantiated) {
 725        if (offset.used) {
 726            let ot;
 727            if (offset.type == "BIGINT") {
 728                ot = "R";
 729            } else if (offset.type == "INT") {
 730                ot= "RI";
 731            } else {
 732                assert(false);
 733            }
 734            ctx.codeBuilder.copyN(left.label, [ot, offset.label], ["R", right.label], right.sizes[0]);
 735        } else {
 736            ctx.codeBuilder.copyN(left.label, ["V", offset.value[0]], ["R", right.label], right.sizes[0]);
 737        }
 738    } else {
 739        if (offset.value[0]>0) {
 740            for (let i=0; i<right.sizes[0]; i++) left.value[offset.value[0] + i] = right.value[i];
 741        } else {
 742            for (let i=0; i<right.sizes[0]; i++) left.value[i] = right.value[i];
 743        }
 744    }
 745}
 746
 747function genAssignement(ctx, ast) {
 748
 749    let lRef;
 750    let sels;
 751
 752    if (ctx.error) return;
 753
 754    if (ast.values[0].type == "PIN") return genPinAssignement(ctx, ast);
 755
 756    if (ast.values[0].type == "DECLARE") {
 757        lRef = gen(ctx, ast.values[0]);
 758        if (ctx.error) return;
 759        sels = [];
 760    } else {
 761        lRef = ast.values[0].refId;
 762        sels = ast.values[0].selectors;
 763    }
 764
 765
 766    const left = ctx.refs[lRef];
 767    if (!left) return ctx.throwError(ast, "Variable does not exists: "+ast.values[0].name);
 768
 769    // Component instantiation is already done.
 770    if (left.type == "COMPONENT") return;
 771
 772    const rRef = gen(ctx, ast.values[1]);
 773    if  (ctx.error) return;
 774
 775    if (left.type == "SIGNAL") return genSignalAssignmen(ctx, ast, lRef, sels, rRef);
 776
 777    if (left.type == "BIGINT") return genVarAssignment(ctx, ast, lRef, sels, rRef);
 778
 779    return ctx.throwError(ast, "Assigning to invalid");
 780}
 781
 782function toRefA_Fr1(ctx, ast, aRef) {
 783    const a = ctx.refs[aRef];
 784    if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
 785    if (a.used) {
 786        if (a.type == "BIGINT") {
 787            return ["R", a.label];
 788        } else {
 789            assert(false);
 790        }
 791    } else {
 792        return ["C", ctx.addConstant(a.value[0])];
 793    }
 794}
 795
 796function toRefA_Int1(ctx, ast, aRef) {
 797    if (aRef <0) return ["CC"];
 798    const a = ctx.refs[aRef];
 799    if (a.sizes[0] != 1) return ctx.throwError(ast, "Expected only one element");
 800    if (a.used) {
 801        if (a.type == "INT") {
 802            return ["RI", a.label];
 803        } else if (a.type == "BIGINT") {
 804            return ["R", a.label];
 805        } else {
 806            assert(false);
 807        }
 808    } else {
 809        return ["V", a.value[0]];
 810    }
 811}
 812
 813
 814function genConstraint(ctx, ast) {
 815    const aRef = gen(ctx, ast.values[0]);
 816    if (ctx.error) return;
 817    const bRef = gen(ctx, ast.values[1]);
 818    if (ctx.error) return;
 819    const strErr = ast.fileName + ":" + ast.first_line + ":" + ast.first_column;
 820
 821    ctx.codeBuilder.checkConstraint(toRefA_Fr1(ctx, ast.values[0], aRef), toRefA_Fr1(ctx, ast.values[1], bRef), strErr);
 822}
 823
 824
 825function genArray(ctx, ast) {
 826    let subSizes;
 827    let instantiate = false;
 828    if (ast.values.length == 0) return ctx.throwError(ast, "Arrays with zero elements not allowed");
 829    const value = [];
 830    const refs = [];
 831    for (let i=0; i<ast.values.length; i++) {
 832        const eRef = gen(ctx, ast.values[i]);
 833        const e = ctx.refs[eRef];
 834
 835        if (i==0) {
 836            subSizes = e.sizes;
 837        } else {
 838            if (!utils.sameSizes(subSizes, e.sizes)) return ctx.throwError(ast, "Heteroeneus array not allowed");
 839        }
 840        if (e.used) {
 841            instantiate = true;
 842        }
 843        if (!instantiate) {
 844            value.push(...e.value);
 845        }
 846        refs.push(eRef);
 847    }
 848
 849    const newSize = [subSizes[0]*ast.values.length , ...subSizes];
 850
 851    if (instantiate) {
 852        const rRef = newRef(ctx, "BIGINT", "_arr", null, newSize);
 853        instantiateRef(ctx, rRef);
 854        for (let i=0; i<ast.values.length; i++) {
 855            const v = ctx.refs[refs[i]];
 856            const r = ctx.refs[rRef];
 857            ctx.codeBuilder.copyN(r.label, ["V", i*subSizes[0]], ["R", v.label], subSizes[0]);
 858        }
 859        return rRef;
 860    } else {
 861        const rRef = newRef(ctx, "BIGINT", "_arr", value, newSize);
 862        return rRef;
 863    }
 864
 865}
 866
 867
 868function genFunctionCall(ctx, ast) {
 869    if (ast.name == "log") {
 870        const vRef = gen(ctx, ast.params[0]);
 871        ctx.codeBuilder.log(toRefA_Fr1(ctx, ast.params[0], vRef));
 872        return vRef;
 873    }
 874    const params = [];
 875    for (let i=0; i<ast.params.length; i++) {
 876        const pRef = gen(ctx, ast.params[i]);
 877        params.push(ctx.refs[pRef]);
 878    }
 879
 880    const fn = ctx.buildFunction(ast.name, params);
 881    if (ctx.error) return;
 882
 883    if (fn.type == "VARVAL_CONSTSIZE") {
 884        const resRef = newRef(ctx, "BIGINT", `_ret${ast.name}`, null, fn.returnSizes);
 885        const res = ctx.refs[resRef];
 886        instantiateRef(ctx, resRef);
 887
 888        const paramLabels = [];
 889        for (let i=0; i<params.length; i++) {
 890            if (params[i].used) paramLabels.push(params[i].label);
 891        }
 892
 893        ctx.codeBuilder.fnCall(fn.fnName, res.label, paramLabels);
 894
 895        return resRef;
 896    } else {
 897        const res = newRef(ctx, "BIGINT", "_retVal", fn.returnValue, fn.returnSizes);
 898        return res;
 899    }
 900}
 901
 902function enterConditionalCode(ctx, ast) {
 903    if (!ctx.conditionalCode) {
 904        iterateAST(ast, (ast) => {
 905            if (ast.type == "OP") {
 906                if (["=", "+=", "*=", "PLUSPLUSLEFT", "PLUSPLUSRIGHT", "MINUSMINUSLEFT", "MINUSMINUSRIGHT"].indexOf(ast.op) >= 0) {
 907                    let refId;
 908                    refId = ast.values[0].refId;
 909                    const ref = ctx.refs[refId];
 910                    instantiateRef(ctx, refId, ref.value);
 911                }
 912            }
 913        });
 914        ctx.conditionalCode = 1;
 915    } else {
 916        ctx.conditionalCode ++;
 917    }
 918}
 919
 920function leaveConditionalCode(ctx) {
 921    assert(ctx.conditionalCode, "Leaving conditional code too many times");
 922    ctx.conditionalCode --;
 923    if (!ctx.conditionalCode) {
 924        delete ctx.conditionalCode;
 925    }
 926}
 927
 928function genLoop(ctx, ast) {
 929    genLoopSrcComment(ctx, ast);
 930    let inLoop = false;
 931
 932    if (ast.init) {
 933        gen(ctx, ast.init);
 934        if (ctx.error) return;
 935    }
 936
 937    let end=false;
 938
 939    let loopCondRef;
 940    let loopCond;
 941    let bodyCode;
 942
 943
 944    const condRef = gen(ctx, ast.condition);
 945    if (ctx.error) return;
 946
 947    const cond = ctx.refs[condRef];
 948    if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
 949
 950    if (cond.used) {
 951        inLoop = true;
 952        enterConditionalCode(ctx, ast);
 953
 954        loopCondRef = newRef(ctx, "BIGINT", "_loopCond");
 955        loopCond = ctx.refs[loopCondRef];
 956        loopCond.used = true;
 957        ctx.fnBuilder.definePFrElement(loopCond.label);
 958        ctx.codeBuilder.assign(loopCond.label, ["R", cond.label], ["V", 0]);
 959    } else {
 960        if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
 961        if (ctx.F.isZero(cond.value[0])) end=true;
 962    }
 963
 964
 965    while (!end) {
 966
 967        const oldCodeBuilder = ctx.codeBuilder;
 968        ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
 969
 970        if (ast.body.type != "BLOCK") genSrcComment(ctx, ast.body);
 971        gen(ctx, ast.body);
 972        if (ctx.error) return;
 973
 974        if (ast.step) {
 975            gen(ctx, ast.step);
 976            if (ctx.error) return;
 977        }
 978
 979        const condRef2 = gen(ctx, ast.condition);
 980        if (ctx.error) return;
 981
 982        const cond2 = ctx.refs[condRef2];
 983
 984        if ((!cond2.used) &&(ctx.codeBuilder.hasCode())) {
 985            instantiateRef(ctx, condRef2, cond2.value);
 986        }
 987
 988        if (!inLoop) {
 989            if (cond2.used) {
 990                oldCodeBuilder.concat(ctx.codeBuilder);
 991                ctx.codeBuilder = oldCodeBuilder;
 992                inLoop = true;
 993                enterConditionalCode(ctx, ast);
 994
 995                loopCondRef = newRef(ctx, "BIGINT", "_loopCond");
 996                loopCond = ctx.refs[loopCondRef];
 997                loopCond.used = true;
 998                ctx.fnBuilder.definePFrElement(loopCond.label);
 999                ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
1000
1001            } else {
1002                oldCodeBuilder.concat(ctx.codeBuilder);
1003                ctx.codeBuilder = oldCodeBuilder;
1004                if (ctx.F.isZero(cond2.value[0])) end=true;
1005            }
1006        } else {
1007            ctx.codeBuilder.assign(loopCond.label, ["R", cond2.label], ["V", 0]);
1008            bodyCode = ctx.codeBuilder;
1009            ctx.codeBuilder = oldCodeBuilder;
1010            end=true;
1011        }
1012    }
1013    if (inLoop) {
1014        ctx.codeBuilder.addLoop(loopCond.label, bodyCode);
1015        leaveConditionalCode(ctx);
1016    }
1017    ctx.scopes.pop();
1018}
1019
1020function genIf(ctx, ast) {
1021    genIfSrcComment(ctx, ast);
1022    const condRef = gen(ctx, ast.condition);
1023    if (ctx.error) return;
1024    const cond = ctx.refs[condRef];
1025    if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
1026
1027    if (cond.used) {
1028        let thenCode, elseCode;
1029        enterConditionalCode(ctx, ast);
1030
1031        const oldCodeBuilder = ctx.codeBuilder;
1032        ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1033
1034        gen(ctx, ast.then);
1035        if (ctx.error) return;
1036
1037        thenCode = ctx.codeBuilder;
1038
1039        if (ast.else) {
1040            ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1041            gen(ctx, ast.else);
1042            if (ctx.error) return;
1043            elseCode = ctx.codeBuilder;
1044        }
1045
1046        ctx.codeBuilder = oldCodeBuilder;
1047        ctx.codeBuilder.addIf(cond.label, thenCode, elseCode);
1048
1049        leaveConditionalCode(ctx);
1050
1051    } else {
1052        if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
1053        if (!ctx.F.isZero(cond.value[0])) {
1054            gen(ctx, ast.then);
1055        } else {
1056            if (ast.else) {
1057                gen(ctx, ast.else);
1058            }
1059        }
1060    }
1061}
1062
1063
1064function genReturn(ctx, ast) {
1065    const vRef = gen(ctx, ast.value);
1066    const v= ctx.refs[vRef];
1067    if (ctx.returnSizes) {
1068        if (!utils.sameSizes(v.sizes, ctx.returnSizes)) return ctx.throwError(ast, "Diferent return sizes");
1069    } else {
1070        ctx.returnSizes = v.sizes;
1071    }
1072    if (ctx.conditionalCode) {
1073        instantiateRef(ctx, vRef, v.value);
1074    }
1075    if (v.used) {
1076        ctx.codeBuilder.copyNRet(["R", v.label], v.sizes[0]);
1077    } else {
1078        if (!utils.isDefined(v.value)) return ctx.throwError(ast, "Returning an unknown value");
1079        if (!utils.isDefined(ctx.returnValue))  {
1080            ctx.returnValue = v.value;
1081        }
1082    }
1083    ctx.codeBuilder.ret();
1084    return vRef;
1085}
1086
1087
1088
1089function genSignalAssignConstraint(ctx, ast) {
1090    const res = genAssignement(ctx, ast);
1091    //    genConstraint(ctx, ast);
1092    return res;
1093    //    return genVarAssignement(ctx, ast);
1094}
1095
1096function genVarAddAssignement(ctx, ast) {
1097    return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "+", values: ast.values}]});
1098}
1099
1100function genVarMulAssignement(ctx, ast) {
1101    return genAssignement(ctx, {values: [ast.values[0], {type: "OP", op: "*", values: ast.values}]});
1102}
1103
1104function genOpOp(ctx, ast, op, lr) {
1105
1106    if (ast.values[0].type != "VARIABLE") return ctx.throwError(ast, "incrementing a non variable");
1107
1108    const vRef = ast.values[0].refId;
1109
1110    const vevalRef = gen(ctx, ast.values[0]);
1111    if (ctx.error) return;
1112    const veval = ctx.refs[vevalRef];
1113
1114    if (veval.type != "BIGINT") return ctx.throwError(ast, "incrementing a non variable");
1115
1116    const resRef = newRef(ctx, "BIGINT", "_tmp");
1117    const res = ctx.refs[resRef];
1118    if (veval.used) {
1119        instantiateRef(ctx, resRef);
1120        ctx.codeBuilder.fieldOp(res.label, op, [["R", veval.label], ["C", ctx.addConstant(ctx.F.one)]]);
1121    } else {
1122        res.value = [ctx.F[op](veval.value[0], ctx.F.one)];
1123    }
1124    genVarAssignment(ctx, ast, vRef, ast.values[0].selectors, resRef);
1125    if (lr == "RIGHT") {
1126        return vevalRef;
1127    } else if (lr == "LEFT") {
1128        return resRef;
1129    }
1130}
1131
1132function genOp(ctx, ast, op, nOps, adjustBool) {
1133    const vals = [];
1134    const valRefs = [];
1135
1136    var anyUsed=false;
1137
1138    for (let i=0; i<nOps; i++) {
1139        const  ref = gen(ctx, ast.values[i]);
1140        if (ctx.error) return;
1141        let v = ctx.refs[ref];
1142        valRefs.push(ref);
1143        vals.push(v);
1144
1145        if (!utils.sameSizes(v.sizes, [1,0])) return ctx.throwError(ast, "Operation cannot be done on an array");
1146        if (  (!v.used)
1147            &&(  (!utils.isDefined(v.value))
1148               ||(!utils.isDefined(v.value[0]))))
1149            return ctx.throwError(ast, "Using a not assigned varialble: ");
1150
1151        if (v.used) anyUsed=true;
1152    }
1153
1154    let rRef;
1155    if (anyUsed) {
1156        const params = [];
1157        for (let i=0; i<nOps; i++) {
1158            params.push(toRefA_Fr1(ctx, ast.values[i], valRefs[i]));
1159        }
1160
1161        rRef = newRef(ctx, "BIGINT", "_tmp");
1162        instantiateRef(ctx, rRef);
1163        const r = ctx.refs[rRef];
1164        ctx.codeBuilder.fieldOp(r.label, op, params);
1165    } else {
1166        const params = [];
1167        for (let i=0; i<nOps; i++) {
1168            params.push(ctx.F.e(vals[i].value[0]));
1169        }
1170
1171        rRef = newRef(ctx, "BIGINT", "_tmp", adjustBool ? (ctx.F[op](...params)?ctx.F.one:ctx.F.zero)  : ctx.F[op](...params));
1172    }
1173    return rRef;
1174}
1175
1176
1177function genTerCon(ctx, ast) {
1178    const condRef = gen(ctx, ast.values[0]);
1179    if (ctx.error) return;
1180    const cond = ctx.refs[condRef];
1181    if (!utils.sameSizes(cond.sizes, [1,0])) return ctx.throwError(ast.condition, "Operation cannot be done on an array");
1182
1183    if (cond.used) {
1184        let thenCode, elseCode;
1185        enterConditionalCode(ctx, ast);
1186
1187        const rLabel = ctx.getUniqueName("_ter");
1188
1189        ctx.fnBuilder.definePFrElement(rLabel);
1190
1191        const oldCodeBuilder = ctx.codeBuilder;
1192        ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1193
1194        const thenRef = gen(ctx, ast.values[1]);
1195        if (ctx.error) return;
1196        const then = ctx.refs[thenRef];
1197
1198        let t;
1199        if (then.used) {
1200            t = ["R", then.label];
1201        } else {
1202            if (then.sizes[0] == 1) {
1203                t = ["C", ctx.addConstant(then.value[0])];
1204            } else {
1205                instantiateRef(ctx, thenRef, then.value);
1206                t = ["R", then.label];
1207            }
1208        }
1209
1210        ctx.codeBuilder.assign(rLabel, t, ["V", 0]);
1211
1212        thenCode = ctx.codeBuilder;
1213        ctx.codeBuilder = ctx.fnBuilder.newCodeBuilder();
1214
1215        const elseRef = gen(ctx, ast.values[2]);
1216        if (ctx.error) return;
1217        const els = ctx.refs[elseRef];
1218
1219        let e;
1220        if (els.used) {
1221            e = ["R", els.label];
1222        } else {
1223            if (els.sizes[0] == 1) {
1224                e = ["C", ctx.addConstant(els.value[0])];
1225            } else {
1226                instantiateRef(ctx, elseRef, els.value);
1227                e = ["R", els.label];
1228            }
1229        }
1230
1231        ctx.codeBuilder.assign(rLabel,  e, ["V", 0]);
1232        elseCode = ctx.codeBuilder;
1233
1234        ctx.codeBuilder = oldCodeBuilder;
1235
1236        ctx.codeBuilder.addIf(cond.label, thenCode, elseCode);
1237
1238
1239        if (!utils.sameSizes(then.sizes, els.sizes)) return ctx.throwError(ast, "Ternary op must return the same sizes");
1240
1241        const refId = ctx.refs.length;
1242        ctx.refs.push({
1243            type: "BIGINT",
1244            sizes: then.sizes,
1245            used: true,
1246            label: rLabel
1247        });
1248
1249        return refId;
1250
1251    } else {
1252        if (!utils.isDefined(cond.value)) return ctx.throwError(ast, "condition value not assigned");
1253        if (!ctx.F.isZero(cond.value[0])) {
1254            return gen(ctx, ast.values[1]);
1255        } else {
1256            return gen(ctx, ast.values[2]);
1257        }
1258    }
1259}
1260
1261function genInclude(ctx, ast) {
1262    return ast.block ? gen(ctx, ast.block) : "";
1263}
1264
1265