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