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