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