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