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