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