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