arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/exec.js
src/exec.jsRaw
   1/*
   2    Copyright 2018 0KIMS association.
   3
   4    This file is part of circom (Zero Knowledge Circuit Compiler).
   5
   6    circom is a free software: you can redistribute it and/or modify it
   7    under the terms of the GNU General Public License as published by
   8    the Free Software Foundation, either version 3 of the License, or
   9    (at your option) any later version.
  10
  11    circom is distributed in the hope that it will be useful, but WITHOUT
  12    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13    or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  14    License for more details.
  15
  16    You should have received a copy of the GNU General Public License
  17    along with circom. If not, see <https://www.gnu.org/licenses/>.
  18*/
  19
  20const path = require("path");
  21const fs = require("fs");
  22
  23const utils = require("./utils");
  24
  25const bigInt = require("big-integer");
  26const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
  27const __MASK__ = new bigInt(2).pow(253).minus(1);
  28
  29const lc = require("./lcalgebra");
  30const parser = require("../parser/jaz.js").parser;
  31
  32/* TODO: Add lines information
  33
  34function setLines(dst, first, last) {
  35    last = last || first;
  36    dst.first_line = first.first_line;
  37    dst.first_column = first.first_column;
  38    dst.last_line = last.last_line;
  39    dst.last_column = last.last_column;
  40}
  41*/
  42
  43module.exports = exec;
  44
  45
  46function exec(ctx, ast) {
  47    if (!ast) {
  48        return error(ctx, ast, "Null AST");
  49    }
  50    if ((ast.type == "NUMBER") || (ast.type == "LINEARCOMBINATION") || (ast.type =="SIGNAL") || (ast.type == "QEQ")) {
  51        return ast;
  52    } else if (ast.type == "VARIABLE") {
  53        return execVariable(ctx, ast);
  54    } else if (ast.type == "PIN") {
  55        return execPin(ctx, ast);
  56    } else if (ast.type == "OP") {
  57        if (ast.op == "=") {
  58            return execVarAssignement(ctx, ast);
  59        } else if (ast.op == "<--") {
  60            return execSignalAssign(ctx, ast);
  61        } else if (ast.op == "<==") {
  62            return execSignalAssignConstrain(ctx, ast);
  63        } else if (ast.op == "===") {
  64            return execConstrain(ctx, ast);
  65        } else if (ast.op == "+=") {
  66            return execVarAddAssignement(ctx, ast);
  67        } else if (ast.op == "*=") {
  68            return execVarMulAssignement(ctx, ast);
  69        } else if (ast.op == "+") {
  70            return execAdd(ctx, ast);
  71        } else if (ast.op == "-") {
  72            return execSub(ctx, ast);
  73        } else if (ast.op == "UMINUS") {
  74            return execUMinus(ctx, ast);
  75        } else if (ast.op == "*") {
  76            return execMul(ctx, ast);
  77        } else if (ast.op == "%") {
  78            return execMod(ctx, ast);
  79        } else if (ast.op == "PLUSPLUSRIGHT") {
  80            return execPlusPlusRight(ctx, ast);
  81        } else if (ast.op == "PLUSPLUSLEFT") {
  82            return execPlusPlusLeft(ctx, ast);
  83        } else if (ast.op == "MINUSMINUSRIGHT") {
  84            return execMinusMinusRight(ctx, ast);
  85        } else if (ast.op == "MINUSMINUSLEFT") {
  86            return execMinusMinusLeft(ctx, ast);
  87        } else if (ast.op == "/") {
  88            return execDiv(ctx, ast);
  89        } else if (ast.op == "\\") {
  90            return execIDiv(ctx, ast);
  91        } else if (ast.op == "**") {
  92            return execExp(ctx, ast);
  93        } else if (ast.op == "&") {
  94            return execBAnd(ctx, ast);
  95        } else if (ast.op == "&&") {
  96            return execAnd(ctx, ast);
  97        } else if (ast.op == "||") {
  98            return execOr(ctx, ast);
  99        } else if (ast.op == "<<") {
 100            return execShl(ctx, ast);
 101        } else if (ast.op == ">>") {
 102            return execShr(ctx, ast);
 103        } else if (ast.op == "<") {
 104            return execLt(ctx, ast);
 105        } else if (ast.op == ">") {
 106            return execGt(ctx, ast);
 107        } else if (ast.op == "<=") {
 108            return execLte(ctx, ast);
 109        } else if (ast.op == ">=") {
 110            return execGte(ctx, ast);
 111        } else if (ast.op == "==") {
 112            return execEq(ctx, ast);
 113        } else if (ast.op == "!=") {
 114            return execNeq(ctx, ast);
 115        } else if (ast.op == "?") {
 116            return execTerCon(ctx, ast);
 117        } else {
 118            error(ctx, ast, "Invalid operation: " + ast.op);
 119        }
 120    } else if (ast.type == "DECLARE") {
 121        if (ast.declareType == "COMPONENT") {
 122            return execDeclareComponent(ctx, ast);
 123        } else if ((ast.declareType == "SIGNALIN")||
 124                   (ast.declareType == "SIGNALOUT")||
 125                   (ast.declareType == "SIGNAL")) {
 126            return execDeclareSignal(ctx, ast);
 127        } else if (ast.declareType == "VARIABLE") {
 128            return execDeclareVariable(ctx, ast);
 129        } else {
 130            error(ctx, ast, "Invalid declaration: " + ast.declareType);
 131        }
 132    } else if (ast.type == "FUNCTIONCALL") {
 133        return execFunctionCall(ctx, ast);
 134    } else if (ast.type == "BLOCK") {
 135        return execBlock(ctx, ast);
 136    } else if (ast.type == "COMPUTE") {
 137        return ;
 138    } else if (ast.type == "FOR") {
 139        return execFor(ctx, ast);
 140    } else if (ast.type == "WHILE") {
 141        return execWhile(ctx, ast);
 142    } else if (ast.type == "IF") {
 143        return execIf(ctx, ast);
 144    } else if (ast.type == "RETURN") {
 145        return execReturn(ctx, ast);
 146    } else if (ast.type == "TEMPLATEDEF") {
 147        return execTemplateDef(ctx, ast);
 148    } else if (ast.type == "FUNCTIONDEF") {
 149        return execFunctionDef(ctx, ast);
 150    } else if (ast.type == "INCLUDE") {
 151        return execInclude(ctx, ast);
 152    } else if (ast.type == "ARRAY") {
 153        return execArray(ctx, ast);
 154    } else {
 155        error(ctx, ast, "Invalid AST node type: " + ast.type);
 156    }
 157}
 158
 159function error(ctx, ast, errStr) {
 160    ctx.error = {
 161        pos:   {
 162            first_line: ast.first_line,
 163            first_column: ast.first_column,
 164            last_line: ast.last_line,
 165            last_column: ast.last_column
 166        },
 167        errStr: errStr,
 168        errFile: ctx.fileName,
 169        ast: ast,
 170        message: errStr
 171    };
 172}
 173
 174function iterateSelectors(ctx, sizes, baseName, fn) {
 175    if (sizes.length == 0) {
 176        return fn(baseName);
 177    }
 178    const res = [];
 179    for (let i=0; i<sizes[0]; i++) {
 180        res.push(iterateSelectors(ctx, sizes.slice(1), baseName+"["+i+"]", fn));
 181        if (ctx.error) return null;
 182    }
 183    return res;
 184}
 185
 186
 187function getScope(ctx, name, selectors) {
 188
 189    const sels = [];
 190    if (selectors) {
 191        for (let i=0; i< selectors.length; i++) {
 192            const idx = exec(ctx, selectors[i]);
 193            if (ctx.error) return;
 194
 195            if (idx.type != "NUMBER") return error(ctx, selectors[i], "expected a number");
 196            sels.push( idx.value.toJSNumber() );
 197        }
 198    }
 199
 200
 201    function select(v, sels) {
 202        if (v.type == "SIGNAL") {
 203            return reduce(v, sels, "sIdx");
 204        } else if (v.type == "COMPONENT") {
 205            return reduce(v, sels, "cIdx");
 206        } else {
 207            const s = sels || [];
 208            if (s.length == 0)  return v;
 209            return select(v[s[0]], s.slice(1));
 210        }
 211    }
 212
 213    for (let i=ctx.scopes.length-1; i>=0; i--) {
 214        if (ctx.scopes[i][name]) return select(ctx.scopes[i][name].value, sels);
 215    }
 216    return null;
 217
 218    function reduce(v, _sels, idxName) {
 219        let sels = _sels || [];
 220        let sizes = v.sizes || [];
 221
 222        let accSizes = [1];
 223        for (let i=sizes.length-1; i>0; i--) {
 224            accSizes = [accSizes[0]*sizes[i], ...accSizes];
 225        }
 226        const res = Object.assign({}, v);
 227        res.sizes = sizes.slice(sels.length);
 228        for (let i=0; i<sels.length; i++) {
 229            res[idxName] += sels[i]*accSizes[i];
 230        }
 231        return res;
 232    }
 233}
 234
 235function getScopeRef(ctx, name, selectors) {
 236
 237    const sels = [];
 238    if (selectors) {
 239        for (let i=0; i< selectors.length; i++) {
 240            const idx = exec(ctx, selectors[i]);
 241            if (ctx.error) return;
 242
 243            if (idx.type != "NUMBER") return error(ctx, selectors[i], "expected a number");
 244            sels.push( idx.value.toJSNumber() );
 245        }
 246    }
 247
 248
 249    function select(v, s, t) {
 250        s = s || [];
 251        if (s.length == 0)  return [v, sels, t];
 252        return select(v[s[0]], s.slice(1), t);
 253    }
 254
 255    for (let i=ctx.scopes.length-1; i>=0; i--) {
 256        if (ctx.scopes[i][name]) return select(ctx.scopes[i][name].value, sels, ctx.scopes[i][name].type);
 257    }
 258    return [null, [], ""];
 259}
 260
 261
 262function setScopeRef(ctx, name, sels, value) {
 263    let l = getScopeLevel(ctx, name);
 264    if (l==-1) l= ctx.scopes.length-1;
 265
 266    if (sels.length == 0) {
 267        ctx.scopes[l][name].value = value;
 268    } else {
 269        setScopeArray(ctx.scopes[l][name].value, sels);
 270    }
 271
 272    function setScopeArray(a, sels) {
 273        if (sels.length == 1) {
 274            a[sels[0]] = value;
 275        } else {
 276            setScopeArray(a[sels[0]], sels.slice(1));
 277        }
 278    }
 279}
 280
 281function getScopeLevel(ctx, name) {
 282    for (let i=ctx.scopes.length-1; i>=0; i--) {
 283        if (ctx.scopes[i][name]) return i;
 284    }
 285    return -1;
 286}
 287
 288function execBlock(ctx,  ast) {
 289    for (let i=0; i<ast.statements.length; i++) {
 290        exec(ctx, ast.statements[i]);
 291        if (ctx.returnValue) return;
 292        if (ctx.error) return;
 293    }
 294}
 295
 296function execTemplateDef(ctx, ast) {
 297    const scope = ctx.scopes[0];  // Lets put templates always in top scope.
 298    //    const scope = ctx.scopes[ctx.scopes.length-1];
 299    if (getScope(ctx, ast.name)) {
 300        return error(ctx, ast, "Name already exists: "+ast.name);
 301    }
 302    scope[ast.name] = {
 303        type: "TEMPLATE",
 304        value: {
 305            type: "TEMPLATE",
 306            params: ast.params,
 307            block: ast.block,
 308            fileName: ctx.fileName,
 309            filePath: ctx.filePath,
 310            scopes: copyScope(ctx.scopes)
 311        }
 312    };
 313    ctx.templates[ast.name] = {
 314        block: ast.block,
 315        params: ast.params
 316    };
 317}
 318
 319function execFunctionDef(ctx, ast) {
 320    const scope = ctx.scopes[0]; // Lets put functions always in top scope.
 321    //    const scope = ctx.scopes[ctx.scopes.length-1];
 322    if (getScope(ctx, ast.name)) {
 323        return error(ctx, ast, "Name already exists: "+ast.name);
 324    }
 325    ctx.functionParams[ast.name] = ast.params;
 326    scope[ast.name] = {
 327        type: "FUNCTION",
 328        value: {
 329            type: "FUNCTION",
 330            params: ast.params,
 331            block: ast.block,
 332            fileName: ctx.fileName,
 333            filePath: ctx.filePath,
 334            scopes: copyScope(ctx.scopes)
 335        }
 336    };
 337    ctx.functions[ast.name] = {
 338        block: ast.block,
 339        params: ast.params
 340    };
 341}
 342
 343
 344function execDeclareComponent(ctx, ast) {
 345    const scope = ctx.scopes[ctx.scopes.length-1];
 346
 347    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
 348    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
 349
 350    const sizes=[];
 351    for (let i=0; i< ast.name.selectors.length; i++) {
 352        const size = exec(ctx, ast.name.selectors[i]);
 353        if (ctx.error) return;
 354
 355        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
 356
 357        sizes.push( size.value.toJSNumber() );
 358    }
 359
 360    const cIdx = ctx.addComponent(ast.name.name, sizes);
 361
 362    scope[ast.name.name] = {
 363        type: "COMPONENT",
 364        value: {
 365            type: "COMPONENT",
 366            sizes: sizes,
 367            cIdx: Array.isArray(cIdx) ? cIdx[0] : cIdx
 368        }
 369    };
 370
 371    return {
 372        type: "VARIABLE",
 373        name: ast.name.name,
 374        selectors: []
 375    };
 376}
 377
 378function execInstantiateComponet(ctx, vr, fn) {
 379
 380    if (vr.type != "VARIABLE") return error(ctx, fn, "Left hand instatiate component must be a variable");
 381    if (fn.type != "FUNCTIONCALL") return error(ctx, fn, "Right type of instantiate component must be a function call");
 382
 383    const componentName = vr.name;
 384    const templateName = fn.name;
 385
 386    const scopeLevel = getScopeLevel(ctx, templateName);
 387    if (scopeLevel == -1) return error(ctx,fn, "Invalid Template");
 388    const template = getScope(ctx, templateName);
 389
 390    if (template.type != "TEMPLATE") return error(ctx, fn, "Invalid Template");
 391
 392
 393    const paramValues = [];
 394    for (let i=0; i< fn.params.length; i++) {
 395        const v = exec(ctx, fn.params[i]);
 396        if (ctx.error) return;
 397
 398        paramValues.push(v);
 399    }
 400    if (template.params.length != paramValues.length) return error(ctx, fn, "Invalid Number of parameters");
 401
 402
 403    const vComp = getScope(ctx, componentName, vr.selectors);
 404    if (vComp.type != "COMPONENT") return error(ctx, fn, "Assigning to a non component");
 405    const cIdx = vComp.cIdx;
 406    if (cIdx == -1) return error(ctx, fn, "Component not defined");
 407    let l=1;
 408    for (let i=0; i<vComp.sizes.length; i++) l = l*vComp.sizes[i];
 409    for (let i=0; i<l; i++) {
 410        instantiateComponent(cIdx+i);
 411    }
 412
 413    function instantiateComponent(cIdx) {
 414
 415        function extractValue(v) {
 416            if (Array.isArray(v)) {
 417                return v.map(extractValue);
 418            } else {
 419                return v.value.toString();
 420            }
 421        }
 422
 423        if (ctx.components[cIdx]) return error(ctx, fn, "Component already instantiated");
 424
 425        const oldComponent = ctx.currentComponent;
 426        const oldFileName = ctx.fileName;
 427        const oldFilePath = ctx.filePath;
 428        const oldMain = ctx.main;
 429
 430        if ((componentName == "main")&&(ctx.currentComponent==-1)) {
 431            ctx.main=true;
 432        } else {
 433            ctx.main=false;
 434        }
 435
 436        ctx.currentComponent = cIdx;
 437
 438        ctx.components[cIdx] = {
 439            params: {},
 440            names: ctx.newTableName(),
 441            nInSignals: 0
 442        };
 443
 444        const oldScopes = ctx.scopes;
 445
 446        ctx.scopes = oldScopes.slice(0, scopeLevel+1);
 447
 448        if (template.params.length != paramValues.length) return error(ctx, fn, "Invalid number of parameters: " + templateName);
 449
 450        const scope = {};
 451        for (let i=0; i< template.params.length; i++) {
 452            scope[template.params[i]] = {
 453                type: "VARIABLE",
 454                value: paramValues[i]
 455            };
 456            ctx.components[cIdx].params[template.params[i]] = extractValue(paramValues[i]);
 457        }
 458
 459        ctx.components[cIdx].template = templateName;
 460        ctx.fileName = template.fileName;
 461        ctx.filePath = template.filePath;
 462        ctx.scopes = copyScope( template.scopes );
 463        ctx.scopes.push(scope);
 464
 465
 466        execBlock(ctx, template.block);
 467
 468        ctx.fileName = oldFileName;
 469        ctx.filePath = oldFilePath;
 470        ctx.currentComponent = oldComponent;
 471        ctx.main = oldMain;
 472        ctx.scopes = oldScopes;
 473    }
 474}
 475
 476function execFunctionCall(ctx, ast) {
 477
 478    if (ast.name == "log") {
 479        const v = exec(ctx, ast.params[0]);
 480        console.log(v.value.toString());
 481        return;
 482    }
 483
 484    const scopeLevel = getScopeLevel(ctx, ast.name);
 485    if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name);
 486    const fnc = getScope(ctx, ast.name);
 487
 488    if (fnc.type != "FUNCTION") return error(ctx, ast, "Not a function: " + ast.name);
 489
 490    const paramValues = [];
 491    for (let i=0; i< ast.params.length; i++) {
 492        const v = exec(ctx, ast.params[i]);
 493        if (ctx.error) return;
 494
 495        paramValues.push(v);
 496    }
 497
 498    if (ast.params.length != paramValues.length) error(ctx, ast, "Invalid Number of parameters");
 499
 500    const oldFileName = ctx.fileName;
 501    const oldFilePath = ctx.filePath;
 502
 503    const oldScopes = ctx.scopes;
 504
 505    ctx.scopes = oldScopes.slice(0, scopeLevel+1);
 506
 507    const scope = {};
 508    for (let i=0; i< fnc.params.length; i++) {
 509        scope[fnc.params[i]] = {
 510            type: "VARIABLE",
 511            value: paramValues[i]
 512        };
 513    }
 514
 515    ctx.fileName = fnc.fileName;
 516    ctx.filePath = fnc.filePath;
 517    ctx.scopes = copyScope( fnc.scopes );
 518    ctx.scopes.push(scope);
 519
 520    execBlock(ctx, fnc.block);
 521
 522    const res = ctx.returnValue;
 523    ctx.returnValue = null;
 524
 525    ctx.fileName = oldFileName;
 526    ctx.filePath = oldFilePath;
 527    ctx.scopes = oldScopes;
 528
 529    return res;
 530}
 531
 532function execReturn(ctx, ast) {
 533    ctx.returnValue = exec(ctx, ast.value);
 534    return;
 535}
 536
 537function execDeclareSignal(ctx, ast) {
 538    const scope = ctx.scopes[ctx.scopes.length-1];
 539
 540    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
 541    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
 542
 543    let totalSize = 1;
 544    const sizes=[];
 545    for (let i=0; i< ast.name.selectors.length; i++) {
 546        const size = exec(ctx, ast.name.selectors[i]);
 547        if (ctx.error) return;
 548
 549        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
 550        const s = size.value.toJSNumber();
 551        totalSize = totalSize * s;
 552        sizes.push( s );
 553    }
 554
 555    let sIdx = ctx.addSignal(ast.name.name, sizes);
 556    if (!Array.isArray(sIdx)) sIdx = [sIdx, sIdx+1];
 557    for (let i=sIdx[0]; i<sIdx[1]; i++) {
 558        ctx.signals[i] = {
 559            o: 0,
 560            e: -1
 561        };
 562
 563        if (ast.declareType == "SIGNALIN") {
 564            ctx.signals[i].o |= ctx.IN;
 565            ctx.components[ctx.currentComponent].nInSignals+=1;
 566        }
 567        if (ast.declareType == "SIGNALOUT") {
 568            ctx.signals[i].o |= ctx.OUT;
 569        }
 570        if (ast.private ) {
 571            ctx.signals[i].o |= ctx.PRV;
 572        }
 573        if (ctx.main) {
 574            ctx.signals[i].o |= ctx.MAIN;
 575        }
 576
 577        // ctx.components[ctx.currentComponent].signals.push(i);
 578    }
 579    scope[ast.name.name] = {
 580        type: "SIGNAL",
 581        value: {
 582            type: "SIGNAL",
 583            sizes: sizes,
 584            sIdx: sIdx[0]
 585        }
 586    };
 587    return {
 588        type: "VARIABLE",
 589        name: ast.name.name,
 590        selectors: []
 591    };
 592}
 593
 594function execDeclareVariable(ctx, ast) {
 595    const scope = ctx.scopes[ctx.scopes.length-1];
 596
 597    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid linear combination name");
 598    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
 599
 600    const sizes=[];
 601    for (let i=0; i< ast.name.selectors.length; i++) {
 602        const size = exec(ctx, ast.name.selectors[i]);
 603        if (ctx.error) return;
 604
 605        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
 606        sizes.push( size.value.toJSNumber() );
 607    }
 608
 609    scope[ast.name.name] = {
 610        type: "VARIABLE",
 611        value: iterateSelectors(ctx, sizes, "", function() {
 612            return {
 613                type: "NUMBER",
 614                value: bigInt(0)
 615            };
 616        })
 617    };
 618
 619    return {
 620        type: "VARIABLE",
 621        name: ast.name.name,
 622        selectors: []
 623    };
 624}
 625
 626function execVariable(ctx, ast) {
 627    let v;
 628    try {
 629        v = getScope(ctx, ast.name, ast.selectors);
 630    } catch(err) {
 631        console.log(JSON.stringify(ast, null,1));
 632    }
 633    if (ctx.error) return;
 634
 635    if (!v) return error(ctx, ast, "Variable not defined");
 636
 637    // If the signal has an assigned value (constant) just return the constant
 638    if ((v.type == "SIGNAL") && (utils.isDefined(ctx.signals[v.sIdx].v))) {
 639        return {
 640            type: "NUMBER",
 641            value: ctx.signals[v.sIdx].v
 642        };
 643    }
 644    let res;
 645    res=v;
 646    return res;
 647}
 648
 649function execPin(ctx, ast) {
 650    const selsC = [];
 651    for (let i=0; i< ast.component.selectors.length; i++) {
 652        const sel = exec(ctx, ast.component.selectors[i]);
 653        if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
 654        selsC.push(sel.value.toJSNumber());
 655    }
 656
 657    const cIdx = ctx.getComponentIdx(ast.component.name, selsC);
 658    if (cIdx<0) return error(ctx, ast.component, "Component does not exists: "+ast.component.name);
 659
 660    const selsP = [];
 661    for (let i=0; i< ast.pin.selectors.length; i++) {
 662        const sel = exec(ctx, ast.pin.selectors[i]);
 663        if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
 664        selsP.push(sel.value.toJSNumber());
 665    }
 666    const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP);
 667
 668    if (sIdx<0) error(ctx, ast, "Signal not defined:" + buildFullName() );
 669    return {
 670        type: "SIGNAL",
 671        sIdx: sIdx
 672    };
 673
 674    function buildFullName() {
 675        return ast.component.name + sels2str(selsC) + "." + ast.pin.name + sels2str(selsP);
 676    }
 677
 678    function sels2str(sels) {
 679        let S = "";
 680        for (let i=0; i< sels.length; i++) {
 681            const sel = exec(ctx, ast.pin.selectors[i]);
 682            if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
 683            S += "[" + sel.value.toString() + "]";
 684        }
 685        return S;
 686    }
 687}
 688
 689function execFor(ctx, ast) {
 690
 691    ctx.scopes.push({});
 692    exec(ctx, ast.init);
 693    if (ctx.error) return;
 694
 695    let v = exec(ctx, ast.condition);
 696    if (ctx.error) return;
 697
 698    if (typeof v.value != "undefined") {
 699        while ((v.value.neq(0))&&(!ctx.returnValue)) {
 700            exec(ctx, ast.body);
 701            if (ctx.error) return;
 702
 703            exec(ctx, ast.step);
 704            if (ctx.error) return;
 705
 706            v = exec(ctx, ast.condition);
 707            if (ctx.error) return;
 708        }
 709    }
 710    ctx.scopes.pop();
 711}
 712
 713function execWhile(ctx, ast) {
 714    let v = exec(ctx, ast.condition);
 715    if (ctx.error) return;
 716
 717    if (typeof v.value != "undefined") {
 718        while ((v.value.neq(0))&&(!ctx.returnValue)) {
 719            exec(ctx, ast.body);
 720            if (ctx.error) return;
 721
 722            v = exec(ctx, ast.condition);
 723            if (ctx.error) return;
 724        }
 725    }
 726}
 727
 728function execIf(ctx, ast) {
 729    let v = exec(ctx, ast.condition);
 730    if (ctx.error) return;
 731
 732    if (typeof v.value != "undefined") {
 733        if ((v.value.neq(0))&&(!ctx.returnValue)) {
 734            exec(ctx, ast.then);
 735            if (ctx.error) return;
 736        } else {
 737            if (ast.else) {
 738                exec(ctx, ast.else);
 739                if (ctx.error) return;
 740            }
 741        }
 742    }
 743}
 744
 745
 746function execVarAssignement(ctx, ast) {
 747    let v;
 748    if (ast.values[0].type == "DECLARE") {
 749        v = exec(ctx, ast.values[0]);
 750        if (ctx.error) return;
 751    } else {
 752        v = ast.values[0];
 753    }
 754    const [num, sels, typ] = getScopeRef(ctx, v.name, v.selectors);
 755    if (ctx.error) return;
 756
 757    if ((typeof(num) != "object")||(num == null)) return  error(ctx, ast, "Variable not defined");
 758
 759    if (typ == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
 760    if (ctx.error) return;
 761    if ((typ == "SIGNAL")&&(ast.op == "=")) return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
 762    if ((["NUMBER", "COMPONENT"].indexOf(typ) >= 0 )&&(ast.op != "=")) return error(ctx, ast, `Cannot assign to a var with ${ast.op}. use = op`);
 763
 764    const res = exec(ctx, ast.values[1]);
 765    if (ctx.error) return;
 766
 767    setScopeRef(ctx, v.name, sels, res);
 768
 769    return v;
 770}
 771
 772function execLt(ctx, ast) {
 773    const a = exec(ctx, ast.values[0]);
 774    if (ctx.error) return;
 775    if (a.type != "NUMBER") return { type: "NUMBER" };
 776    const b = exec(ctx, ast.values[1]);
 777    if (ctx.error) return;
 778    if (b.type != "NUMBER") return { type: "NUMBER" };
 779    if (!a.value || !b.value) return { type: "NUMBER" };
 780    return {
 781        type: "NUMBER",
 782        value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
 783    };
 784}
 785
 786function execGt(ctx, ast) {
 787    const a = exec(ctx, ast.values[0]);
 788    if (ctx.error) return;
 789    if (a.type != "NUMBER") return { type: "NUMBER" };
 790    const b = exec(ctx, ast.values[1]);
 791    if (ctx.error) return;
 792    if (b.type != "NUMBER") return { type: "NUMBER" };
 793    if (!a.value || !b.value) return { type: "NUMBER" };
 794    return {
 795        type: "NUMBER",
 796        value: a.value.gt(b.value) ? bigInt(1) : bigInt(0)
 797    };
 798}
 799
 800function execLte(ctx, ast) {
 801    const a = exec(ctx, ast.values[0]);
 802    if (ctx.error) return;
 803    if (a.type != "NUMBER") return { type: "NUMBER" };
 804    const b = exec(ctx, ast.values[1]);
 805    if (ctx.error) return;
 806    if (b.type != "NUMBER") return { type: "NUMBER" };
 807    if (!a.value || !b.value) return { type: "NUMBER" };
 808    return {
 809        type: "NUMBER",
 810        value: a.value.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0)
 811    };
 812}
 813
 814function execGte(ctx, ast) {
 815    const a = exec(ctx, ast.values[0]);
 816    if (ctx.error) return;
 817    if (a.type != "NUMBER") return { type: "NUMBER" };
 818    const b = exec(ctx, ast.values[1]);
 819    if (ctx.error) return;
 820    if (b.type != "NUMBER") return { type: "NUMBER" };
 821    if (!a.value || !b.value) return { type: "NUMBER" };
 822    return {
 823        type: "NUMBER",
 824        value: a.value.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0)
 825    };
 826}
 827
 828
 829function execEq(ctx, ast) {
 830    const a = exec(ctx, ast.values[0]);
 831    if (ctx.error) return;
 832    if (a.type != "NUMBER") return { type: "NUMBER" };
 833    const b = exec(ctx, ast.values[1]);
 834    if (ctx.error) return;
 835    if (b.type != "NUMBER") return { type: "NUMBER" };
 836    if (!a.value || !b.value) return { type: "NUMBER" };
 837    return {
 838        type: "NUMBER",
 839        value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
 840    };
 841}
 842
 843function execNeq(ctx, ast) {
 844    const a = exec(ctx, ast.values[0]);
 845    if (ctx.error) return;
 846    if (a.type != "NUMBER") return { type: "NUMBER" };
 847    const b = exec(ctx, ast.values[1]);
 848    if (ctx.error) return;
 849    if (b.type != "NUMBER") return { type: "NUMBER" };
 850    if (!a.value || !b.value) return { type: "NUMBER" };
 851    return {
 852        type: "NUMBER",
 853        value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
 854    };
 855}
 856
 857
 858function execBAnd(ctx, ast) {
 859    const a = exec(ctx, ast.values[0]);
 860    if (ctx.error) return;
 861    if (a.type != "NUMBER") return { type: "NUMBER" };
 862    const b = exec(ctx, ast.values[1]);
 863    if (ctx.error) return;
 864    if (b.type != "NUMBER") return { type: "NUMBER" };
 865    if (!a.value || !b.value) return { type: "NUMBER" };
 866    return {
 867        type: "NUMBER",
 868        value: a.value.and(b.value).and(__MASK__)
 869    };
 870}
 871
 872function execAnd(ctx, ast) {
 873    const a = exec(ctx, ast.values[0]);
 874    if (ctx.error) return;
 875    if (a.type != "NUMBER") return { type: "NUMBER" };
 876    const b = exec(ctx, ast.values[1]);
 877    if (ctx.error) return;
 878    if (b.type != "NUMBER") return { type: "NUMBER" };
 879    if (!a.value || !b.value) return { type: "NUMBER" };
 880    return {
 881        type: "NUMBER",
 882        value: (a.value.neq(0) && b.value.neq(0)) ? bigInt(1) : bigInt(0)
 883    };
 884}
 885
 886function execOr(ctx, ast) {
 887    const a = exec(ctx, ast.values[0]);
 888    if (ctx.error) return;
 889    if (a.type != "NUMBER") return { type: "NUMBER" };
 890    const b = exec(ctx, ast.values[1]);
 891    if (ctx.error) return;
 892    if (b.type != "NUMBER") return { type: "NUMBER" };
 893    if (!a.value || !b.value) return { type: "NUMBER" };
 894    return {
 895        type: "NUMBER",
 896        value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0)
 897    };
 898}
 899
 900function execShl(ctx, ast) {
 901    const a = exec(ctx, ast.values[0]);
 902    if (ctx.error) return;
 903    if (a.type != "NUMBER") return { type: "NUMBER" };
 904    const b = exec(ctx, ast.values[1]);
 905    if (ctx.error) return;
 906    if (b.type != "NUMBER") return { type: "NUMBER" };
 907    if (!a.value || !b.value) return { type: "NUMBER" };
 908    const v = b.value.greater(256) ? 256 : b.value.value;
 909    return {
 910        type: "NUMBER",
 911        value: a.value.shiftLeft(v).and(__MASK__)
 912    };
 913}
 914
 915function execShr(ctx, ast) {
 916    const a = exec(ctx, ast.values[0]);
 917    if (ctx.error) return;
 918    if (a.type != "NUMBER") return { type: "NUMBER" };
 919    const b = exec(ctx, ast.values[1]);
 920    if (ctx.error) return;
 921    if (b.type != "NUMBER") return { type: "NUMBER" };
 922    if (!a.value || !b.value) return { type: "NUMBER" };
 923    const v = b.value.greater(256) ? 256 : b.value.value;
 924    return {
 925        type: "NUMBER",
 926        value: a.value.shiftRight(v).and(__MASK__)
 927    };
 928}
 929
 930function execMod(ctx, ast) {
 931    const a = exec(ctx, ast.values[0]);
 932    if (ctx.error) return;
 933    if (a.type != "NUMBER") return { type: "NUMBER" };
 934    const b = exec(ctx, ast.values[1]);
 935    if (ctx.error) return;
 936    if (b.type != "NUMBER") return { type: "NUMBER" };
 937    if (!a.value || !b.value) return { type: "NUMBER" };
 938    return {
 939        type: "NUMBER",
 940        value: a.value.mod(b.value)
 941    };
 942}
 943
 944
 945function execExp(ctx, ast) {
 946    const a = exec(ctx, ast.values[0]);
 947    if (ctx.error) return;
 948    if (a.type != "NUMBER") return { type: "NUMBER" };
 949    const b = exec(ctx, ast.values[1]);
 950    if (ctx.error) return;
 951    if (b.type != "NUMBER") return { type: "NUMBER" };
 952    if (!a.value || !b.value) return { type: "NUMBER" };
 953    return {
 954        type: "NUMBER",
 955        value: a.value.modPow(b.value, __P__)
 956    };
 957}
 958
 959function execDiv(ctx, ast) {
 960    const a = exec(ctx, ast.values[0]);
 961    if (ctx.error) return;
 962    if (a.type != "NUMBER") return { type: "NUMBER" };
 963    const b = exec(ctx, ast.values[1]);
 964    if (ctx.error) return;
 965    if (b.type != "NUMBER") return { type: "NUMBER" };
 966    if (!a.value || !b.value) return { type: "NUMBER" };
 967    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 968    return {
 969        type: "NUMBER",
 970        value: a.value.times(b.value.modInv(__P__)).mod(__P__)
 971    };
 972}
 973
 974function execIDiv(ctx, ast) {
 975    const a = exec(ctx, ast.values[0]);
 976    if (ctx.error) return;
 977    if (a.type != "NUMBER") return { type: "NUMBER" };
 978    const b = exec(ctx, ast.values[1]);
 979    if (ctx.error) return;
 980    if (b.type != "NUMBER") return { type: "NUMBER" };
 981    if (!a.value || !b.value) return { type: "NUMBER" };
 982    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 983    return {
 984        type: "NUMBER",
 985        value: a.value.divide(b.value)
 986    };
 987}
 988
 989function execAdd(ctx, ast) {
 990    const a = exec(ctx, ast.values[0]);
 991    if (ctx.error) return;
 992    const b = exec(ctx, ast.values[1]);
 993    if (ctx.error) return;
 994
 995    const res = lc.add(a,b);
 996    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 997
 998    return res;
 999}
1000
1001function execSub(ctx, ast) {
1002    const a = exec(ctx, ast.values[0]);
1003    if (ctx.error) return;
1004    const b = exec(ctx, ast.values[1]);
1005    if (ctx.error) return;
1006
1007    const res = lc.sub(a,b);
1008    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1009
1010    return res;
1011}
1012
1013function execUMinus(ctx, ast) {
1014    const a = exec(ctx, ast.values[0]);
1015    if (ctx.error) return;
1016
1017    const res = lc.negate(a);
1018    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1019
1020    return res;
1021}
1022
1023function execMul(ctx, ast) {
1024    const a = exec(ctx, ast.values[0]);
1025    if (ctx.error) return;
1026    const b = exec(ctx, ast.values[1]);
1027    if (ctx.error) return;
1028
1029    const res = lc.mul(a,b);
1030    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1031
1032    return res;
1033}
1034
1035
1036function execVarAddAssignement(ctx, ast) {
1037    const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
1038    if (ctx.error) return;
1039    return execVarAssignement(ctx, { op:"=", values: [ast.values[0], res] });
1040}
1041
1042function execVarMulAssignement(ctx, ast) {
1043    const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
1044    if (ctx.error) return;
1045    return execVarAssignement(ctx, { op:"=", values: [ast.values[0], res] });
1046}
1047
1048function execPlusPlusRight(ctx, ast) {
1049    const resBefore = exec(ctx, ast.values[0]);
1050    if (ctx.error) return;
1051    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1052    if (ctx.error) return;
1053    execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1054    return resBefore;
1055}
1056
1057function execPlusPlusLeft(ctx, ast) {
1058    if (ctx.error) return;
1059    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1060    if (ctx.error) return;
1061    execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1062    return resAfter;
1063}
1064
1065function execMinusMinusRight(ctx, ast) {
1066    const resBefore = exec(ctx, ast.values[0]);
1067    if (ctx.error) return;
1068    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1069    if (ctx.error) return;
1070    execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1071    return resBefore;
1072}
1073
1074function execMinusMinusLeft(ctx, ast) {
1075    if (ctx.error) return;
1076    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1077    if (ctx.error) return;
1078    execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1079    return resAfter;
1080}
1081
1082function execTerCon(ctx, ast) {
1083    const cond = exec(ctx, ast.values[0]);
1084    if (ctx.error) return;
1085
1086    if (!cond.value) return { type: "NUMBER" };
1087
1088    if (cond.value.neq(0)) {
1089        return exec(ctx, ast.values[1]);
1090    } else {
1091        return exec(ctx, ast.values[2]);
1092    }
1093}
1094
1095function execSignalAssign(ctx, ast) {
1096    let vDest;
1097    if (ast.values[0].type == "DECLARE") {
1098        vDest = exec(ctx, ast.values[0]);
1099        if (ctx.error) return;
1100    } else {
1101        vDest = ast.values[0];
1102    }
1103
1104    let dst;
1105    if (vDest.type == "VARIABLE") {
1106        dst = getScope(ctx, vDest.name, vDest.selectors);
1107        if (ctx.error) return;
1108    } else if (vDest.type == "PIN") {
1109        dst = execPin(ctx, vDest);
1110        if (ctx.error) return;
1111    } else {
1112        error(ctx, ast, "Bad assignement");
1113    }
1114
1115    if (!dst) return  error(ctx, ast, "Signal not defined");
1116    if (dst.type != "SIGNAL") return  error(ctx, ast, "Signal assigned to a non signal");
1117
1118    let sDest=ctx.signals[dst.sIdx];
1119    if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.sIdx);
1120
1121    let isOut = (sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT);
1122    while (sDest.e>=0) {
1123        sDest=ctx.signals[sDest.e];
1124        isOut = isOut || ((sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT));
1125    }
1126
1127    if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
1128
1129    let src = exec(ctx, ast.values[1]);
1130    if (ctx.error) return;
1131
1132
1133    /*
1134    let vSrc;
1135    if (ast.values[1].type == "DECLARE") {
1136        vSrc = exec(ctx, ast.values[1]);
1137        if (ctx.error) return;
1138    } else {
1139        vSrc = ast.values[1];
1140    }
1141
1142    if (vSrc.type == "VARIABLE") {
1143        src = getScope(ctx, vSrc.name, vSrc.selectors);
1144        if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
1145        if (ctx.error) return;
1146    } else if (vSrc.type == "PIN") {
1147        src = execPin(ctx, vSrc);
1148    }
1149    */
1150
1151    let assignValue = true;
1152    if (src.type == "SIGNAL") {
1153        let sSrc = ctx.signals[src.sIdx];
1154        let isIn  = (sSrc.o & ctx.main)&&(sSrc.o & ctx.IN);
1155        while (sSrc.e>=0) {
1156            sSrc=ctx.signals[sSrc.e];
1157            isIn = isIn || ((sSrc.o & ctx.main)&&(sSrc.o & ctx.IN));
1158        }
1159
1160        // Skip if an out is assigned directly to an input.
1161        if ((!isIn)||(!isOut)) {
1162            sDest.e = src.sIdx;
1163            while (sDest.e >= 0) sDest=ctx.signals[sDest.e];
1164            assignValue = false;
1165        }
1166    }
1167
1168    if (assignValue) {
1169        //        const resLC = exec(ctx, vSrc);
1170        if (ctx.error) return;
1171
1172        //        const v = lc.evaluate(ctx, resLC);
1173        const v = lc.evaluate(ctx, src);
1174
1175        if (v.value) {
1176            sDest.v = v.value;
1177        }
1178    }
1179
1180    return vDest;
1181}
1182
1183function execConstrain(ctx, ast) {
1184    ast.fileName = ctx.fileName;
1185    ast.filePath = ctx.filePath;
1186    const a = exec(ctx, ast.values[0]);
1187    if (ctx.error) return;
1188    const b = exec(ctx, ast.values[1]);
1189    if (ctx.error) return;
1190
1191    const res = lc.sub(a,b);
1192    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1193
1194    if (!lc.isZero(res)) {
1195        ctx.constraints.push(lc.toQEQ(res));
1196    }
1197
1198    if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
1199
1200    return res;
1201}
1202
1203function execSignalAssignConstrain(ctx, ast) {
1204    const v = execSignalAssign(ctx,ast);
1205    if (ctx.error) return;
1206    execConstrain(ctx, ast);
1207    if (ctx.error) return;
1208    return v;
1209}
1210
1211function execInclude(ctx, ast) {
1212    const incFileName = path.resolve(ctx.filePath, ast.file);
1213    const incFilePath = path.dirname(incFileName);
1214
1215    ctx.includedFiles = ctx.includedFiles || [];
1216    if (ctx.includedFiles[incFileName]) return;
1217
1218
1219    const src = fs.readFileSync(incFileName, "utf8");
1220
1221    ctx.includedFiles[incFileName] = src.split("\n");
1222
1223    if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
1224
1225    const incAst = parser.parse(src);
1226
1227    const oldFilePath = ctx.filePath;
1228    const oldFileName = ctx.fileName;
1229    ctx.filePath = incFilePath;
1230    ctx.fileName = incFileName;
1231
1232    exec(ctx, incAst);
1233
1234    ast.block = incAst;
1235
1236    ctx.filePath = oldFilePath;
1237    ctx.fileName = oldFileName;
1238}
1239
1240function execArray(ctx, ast) {
1241    const res = [];
1242
1243    for (let i=0; i<ast.values.length; i++) {
1244        res.push(exec(ctx, ast.values[i]));
1245    }
1246
1247    return res;
1248}
1249
1250function copyScope(scope) {
1251    var scopesClone = [];
1252    for (let i=0; i<scope.length; i++) {
1253        scopesClone.push(scope[i]);
1254    }
1255    return scopesClone;
1256}
1257