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