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