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