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