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