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