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") return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
 713
 714    const res = exec(ctx, ast.values[1]);
 715    if (ctx.error) return;
 716
 717    setScope(ctx, v.name, v.selectors, res);
 718
 719    return v;
 720}
 721
 722function execLt(ctx, ast) {
 723    const a = exec(ctx, ast.values[0]);
 724    if (ctx.error) return;
 725    if (a.type != "NUMBER") return { type: "NUMBER" };
 726    const b = exec(ctx, ast.values[1]);
 727    if (ctx.error) return;
 728    if (b.type != "NUMBER") return { type: "NUMBER" };
 729    if (!a.value || !b.value) return { type: "NUMBER" };
 730    return {
 731        type: "NUMBER",
 732        value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
 733    };
 734}
 735
 736function execGt(ctx, ast) {
 737    const a = exec(ctx, ast.values[0]);
 738    if (ctx.error) return;
 739    if (a.type != "NUMBER") return { type: "NUMBER" };
 740    const b = exec(ctx, ast.values[1]);
 741    if (ctx.error) return;
 742    if (b.type != "NUMBER") return { type: "NUMBER" };
 743    if (!a.value || !b.value) return { type: "NUMBER" };
 744    return {
 745        type: "NUMBER",
 746        value: a.value.gt(b.value) ? bigInt(1) : bigInt(0)
 747    };
 748}
 749
 750function execLte(ctx, ast) {
 751    const a = exec(ctx, ast.values[0]);
 752    if (ctx.error) return;
 753    if (a.type != "NUMBER") return { type: "NUMBER" };
 754    const b = exec(ctx, ast.values[1]);
 755    if (ctx.error) return;
 756    if (b.type != "NUMBER") return { type: "NUMBER" };
 757    if (!a.value || !b.value) return { type: "NUMBER" };
 758    return {
 759        type: "NUMBER",
 760        value: a.value.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0)
 761    };
 762}
 763
 764function execGte(ctx, ast) {
 765    const a = exec(ctx, ast.values[0]);
 766    if (ctx.error) return;
 767    if (a.type != "NUMBER") return { type: "NUMBER" };
 768    const b = exec(ctx, ast.values[1]);
 769    if (ctx.error) return;
 770    if (b.type != "NUMBER") return { type: "NUMBER" };
 771    if (!a.value || !b.value) return { type: "NUMBER" };
 772    return {
 773        type: "NUMBER",
 774        value: a.value.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0)
 775    };
 776}
 777
 778
 779function execEq(ctx, ast) {
 780    const a = exec(ctx, ast.values[0]);
 781    if (ctx.error) return;
 782    if (a.type != "NUMBER") return { type: "NUMBER" };
 783    const b = exec(ctx, ast.values[1]);
 784    if (ctx.error) return;
 785    if (b.type != "NUMBER") return { type: "NUMBER" };
 786    if (!a.value || !b.value) return { type: "NUMBER" };
 787    return {
 788        type: "NUMBER",
 789        value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
 790    };
 791}
 792
 793function execNeq(ctx, ast) {
 794    const a = exec(ctx, ast.values[0]);
 795    if (ctx.error) return;
 796    if (a.type != "NUMBER") return { type: "NUMBER" };
 797    const b = exec(ctx, ast.values[1]);
 798    if (ctx.error) return;
 799    if (b.type != "NUMBER") return { type: "NUMBER" };
 800    if (!a.value || !b.value) return { type: "NUMBER" };
 801    return {
 802        type: "NUMBER",
 803        value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
 804    };
 805}
 806
 807
 808function execBAnd(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.and(b.value).and(__MASK__)
 819    };
 820}
 821
 822function execAnd(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.neq(0) && b.value.neq(0)) ? bigInt(1) : bigInt(0)
 833    };
 834}
 835
 836function execOr(ctx, ast) {
 837    const a = exec(ctx, ast.values[0]);
 838    if (ctx.error) return;
 839    if (a.type != "NUMBER") return { type: "NUMBER" };
 840    const b = exec(ctx, ast.values[1]);
 841    if (ctx.error) return;
 842    if (b.type != "NUMBER") return { type: "NUMBER" };
 843    if (!a.value || !b.value) return { type: "NUMBER" };
 844    return {
 845        type: "NUMBER",
 846        value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0)
 847    };
 848}
 849
 850function execShl(ctx, ast) {
 851    const a = exec(ctx, ast.values[0]);
 852    if (ctx.error) return;
 853    if (a.type != "NUMBER") return { type: "NUMBER" };
 854    const b = exec(ctx, ast.values[1]);
 855    if (ctx.error) return;
 856    if (b.type != "NUMBER") return { type: "NUMBER" };
 857    if (!a.value || !b.value) return { type: "NUMBER" };
 858    const v = b.value.greater(256) ? 256 : b.value.value;
 859    return {
 860        type: "NUMBER",
 861        value: a.value.shiftLeft(v).and(__MASK__)
 862    };
 863}
 864
 865function execShr(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    const v = b.value.greater(256) ? 256 : b.value.value;
 874    return {
 875        type: "NUMBER",
 876        value: a.value.shiftRight(v).and(__MASK__)
 877    };
 878}
 879
 880function execMod(ctx, ast) {
 881    const a = exec(ctx, ast.values[0]);
 882    if (ctx.error) return;
 883    if (a.type != "NUMBER") return { type: "NUMBER" };
 884    const b = exec(ctx, ast.values[1]);
 885    if (ctx.error) return;
 886    if (b.type != "NUMBER") return { type: "NUMBER" };
 887    if (!a.value || !b.value) return { type: "NUMBER" };
 888    return {
 889        type: "NUMBER",
 890        value: a.value.mod(b.value)
 891    };
 892}
 893
 894
 895function execExp(ctx, ast) {
 896    const a = exec(ctx, ast.values[0]);
 897    if (ctx.error) return;
 898    if (a.type != "NUMBER") return { type: "NUMBER" };
 899    const b = exec(ctx, ast.values[1]);
 900    if (ctx.error) return;
 901    if (b.type != "NUMBER") return { type: "NUMBER" };
 902    if (!a.value || !b.value) return { type: "NUMBER" };
 903    return {
 904        type: "NUMBER",
 905        value: a.value.modPow(b.value, __P__)
 906    };
 907}
 908
 909function execDiv(ctx, ast) {
 910    const a = exec(ctx, ast.values[0]);
 911    if (ctx.error) return;
 912    if (a.type != "NUMBER") return { type: "NUMBER" };
 913    const b = exec(ctx, ast.values[1]);
 914    if (ctx.error) return;
 915    if (b.type != "NUMBER") return { type: "NUMBER" };
 916    if (!a.value || !b.value) return { type: "NUMBER" };
 917    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 918    return {
 919        type: "NUMBER",
 920        value: a.value.times(b.value.modInv(__P__)).mod(__P__)
 921    };
 922}
 923
 924function execIDiv(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    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 933    return {
 934        type: "NUMBER",
 935        value: a.value.divide(b.value)
 936    };
 937}
 938
 939function execAdd(ctx, ast) {
 940    const a = exec(ctx, ast.values[0]);
 941    if (ctx.error) return;
 942    const b = exec(ctx, ast.values[1]);
 943    if (ctx.error) return;
 944
 945    const res = lc.add(a,b);
 946    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 947
 948    return res;
 949}
 950
 951function execSub(ctx, ast) {
 952    const a = exec(ctx, ast.values[0]);
 953    if (ctx.error) return;
 954    const b = exec(ctx, ast.values[1]);
 955    if (ctx.error) return;
 956
 957    const res = lc.sub(a,b);
 958    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 959
 960    return res;
 961}
 962
 963function execUMinus(ctx, ast) {
 964    const a = exec(ctx, ast.values[0]);
 965    if (ctx.error) return;
 966
 967    const res = lc.negate(a);
 968    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 969
 970    return res;
 971}
 972
 973function execMul(ctx, ast) {
 974    const a = exec(ctx, ast.values[0]);
 975    if (ctx.error) return;
 976    const b = exec(ctx, ast.values[1]);
 977    if (ctx.error) return;
 978
 979    const res = lc.mul(a,b);
 980    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 981
 982    return res;
 983}
 984
 985
 986function execVarAddAssignement(ctx, ast) {
 987    const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
 988    if (ctx.error) return;
 989    return execVarAssignement(ctx, { values: [ast.values[0], res] });
 990}
 991
 992function execVarMulAssignement(ctx, ast) {
 993    const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
 994    if (ctx.error) return;
 995    return execVarAssignement(ctx, { values: [ast.values[0], res] });
 996}
 997
 998function execPlusPlusRight(ctx, ast) {
 999    const resBefore = exec(ctx, ast.values[0]);
1000    if (ctx.error) return;
1001    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1002    if (ctx.error) return;
1003    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
1004    return resBefore;
1005}
1006
1007function execPlusPlusLeft(ctx, ast) {
1008    if (ctx.error) return;
1009    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1010    if (ctx.error) return;
1011    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
1012    return resAfter;
1013}
1014
1015function execMinusMinusRight(ctx, ast) {
1016    const resBefore = exec(ctx, ast.values[0]);
1017    if (ctx.error) return;
1018    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1019    if (ctx.error) return;
1020    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
1021    return resBefore;
1022}
1023
1024function execMinusMinusLeft(ctx, ast) {
1025    if (ctx.error) return;
1026    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1027    if (ctx.error) return;
1028    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
1029    return resAfter;
1030}
1031
1032function execTerCon(ctx, ast) {
1033    const cond = exec(ctx, ast.values[0]);
1034    if (ctx.error) return;
1035
1036    if (!cond.value) return { type: "NUMBER" };
1037
1038    if (cond.value.neq(0)) {
1039        return exec(ctx, ast.values[1]);
1040    } else {
1041        return exec(ctx, ast.values[2]);
1042    }
1043}
1044
1045function execSignalAssign(ctx, ast) {
1046    let vDest;
1047    if (ast.values[0].type == "DECLARE") {
1048        vDest = exec(ctx, ast.values[0]);
1049        if (ctx.error) return;
1050    } else {
1051        vDest = ast.values[0];
1052    }
1053
1054    let dst;
1055    if (vDest.type == "VARIABLE") {
1056        dst = getScope(ctx, vDest.name, vDest.selectors);
1057        if (ctx.error) return;
1058    } else if (vDest.type == "PIN") {
1059        dst = execPin(ctx, vDest);
1060        if (ctx.error) return;
1061    } else {
1062        error(ctx, ast, "Bad assignement");
1063    }
1064
1065    if (!dst) return  error(ctx, ast, "Signal not defined");
1066    if (dst.type != "SIGNAL") return  error(ctx, ast, "Signal assigned to a non signal");
1067
1068    let sDest=ctx.signals[dst.sIdx];
1069    if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.sIdx);
1070
1071    let isOut = (sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT);
1072    while (sDest.e>=0) {
1073        sDest=ctx.signals[sDest.e];
1074        isOut = isOut || ((sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT));
1075    }
1076
1077    if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
1078
1079    let src = exec(ctx, ast.values[1]);
1080    if (ctx.error) return;
1081
1082
1083    /*
1084    let vSrc;
1085    if (ast.values[1].type == "DECLARE") {
1086        vSrc = exec(ctx, ast.values[1]);
1087        if (ctx.error) return;
1088    } else {
1089        vSrc = ast.values[1];
1090    }
1091
1092    if (vSrc.type == "VARIABLE") {
1093        src = getScope(ctx, vSrc.name, vSrc.selectors);
1094        if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
1095        if (ctx.error) return;
1096    } else if (vSrc.type == "PIN") {
1097        src = execPin(ctx, vSrc);
1098    }
1099    */
1100
1101    let assignValue = true;
1102    if (src.type == "SIGNAL") {
1103        let sSrc = ctx.signals[src.sIdx];
1104        let isIn  = (sSrc.o & ctx.main)&&(sSrc.o & ctx.IN);
1105        while (sSrc.e>=0) {
1106            sSrc=ctx.signals[sSrc.e];
1107            isIn = isIn || ((sSrc.o & ctx.main)&&(sSrc.o & ctx.IN));
1108        }
1109
1110        // Skip if an out is assigned directly to an input.
1111        if ((!isIn)||(!isOut)) {
1112            sDest.e = src.sIdx;
1113            while (sDest.e >= 0) sDest=ctx.signals[sDest.e];
1114            assignValue = false;
1115        }
1116    }
1117
1118    if (assignValue) {
1119        //        const resLC = exec(ctx, vSrc);
1120        if (ctx.error) return;
1121
1122        //        const v = lc.evaluate(ctx, resLC);
1123        const v = lc.evaluate(ctx, src);
1124
1125        if (v.value) {
1126            sDest.v = v.value;
1127        }
1128    }
1129
1130    return vDest;
1131}
1132
1133function execConstrain(ctx, ast) {
1134    ast.fileName = ctx.fileName;
1135    ast.filePath = ctx.filePath;
1136    const a = exec(ctx, ast.values[0]);
1137    if (ctx.error) return;
1138    const b = exec(ctx, ast.values[1]);
1139    if (ctx.error) return;
1140
1141    const res = lc.sub(a,b);
1142    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1143
1144    if (!lc.isZero(res)) {
1145        ctx.constraints.push(lc.toQEQ(res));
1146    }
1147
1148    if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
1149
1150    return res;
1151}
1152
1153function execSignalAssignConstrain(ctx, ast) {
1154    const v = execSignalAssign(ctx,ast);
1155    if (ctx.error) return;
1156    execConstrain(ctx, ast);
1157    if (ctx.error) return;
1158    return v;
1159}
1160
1161function execInclude(ctx, ast) {
1162    const incFileName = path.resolve(ctx.filePath, ast.file);
1163    const incFilePath = path.dirname(incFileName);
1164
1165    ctx.includedFiles = ctx.includedFiles || [];
1166    if (ctx.includedFiles[incFileName]) return;
1167
1168
1169    const src = fs.readFileSync(incFileName, "utf8");
1170
1171    ctx.includedFiles[incFileName] = src.split("\n");
1172
1173    if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
1174
1175    const incAst = parser.parse(src);
1176
1177    const oldFilePath = ctx.filePath;
1178    const oldFileName = ctx.fileName;
1179    ctx.filePath = incFilePath;
1180    ctx.fileName = incFileName;
1181
1182    exec(ctx, incAst);
1183
1184    ast.block = incAst;
1185
1186    ctx.filePath = oldFilePath;
1187    ctx.fileName = oldFileName;
1188}
1189
1190function execArray(ctx, ast) {
1191    const res = [];
1192
1193    for (let i=0; i<ast.values.length; i++) {
1194        res.push(exec(ctx, ast.values[i]));
1195    }
1196
1197    return res;
1198}
1199
1200function copyScope(scope) {
1201    var scopesClone = [];
1202    for (let i=0; i<scope.length; i++) {
1203        scopesClone.push(scope[i]);
1204    }
1205    return scopesClone;
1206}
1207