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