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