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