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    if (ast.name == "log") {
 401        const v = exec(ctx, ast.params[0]);
 402        console.log(v.value.toString());
 403        return;
 404    }
 405
 406    const scopeLevel = getScopeLevel(ctx, ast.name);
 407    if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name);
 408    const fnc = getScope(ctx, ast.name);
 409
 410    if (fnc.type != "FUNCTION") return error(ctx, ast, "Not a function: " + ast.name);
 411
 412    const paramValues = [];
 413    for (let i=0; i< ast.params.length; i++) {
 414        const v = exec(ctx, ast.params[i]);
 415        if (ctx.error) return;
 416
 417        paramValues.push(v);
 418    }
 419
 420    if (ast.params.length != paramValues.length) error(ctx, ast, "Invalid Number of parameters");
 421
 422    const oldFileName = ctx.fileName;
 423    const oldFilePath = ctx.filePath;
 424
 425    const oldScopes = ctx.scopes;
 426
 427    ctx.scopes = oldScopes.slice(0, scopeLevel+1);
 428
 429    const scope = {};
 430    for (let i=0; i< fnc.params.length; i++) {
 431        scope[fnc.params[i]] = paramValues[i];
 432    }
 433
 434    ctx.fileName = fnc.fileName;
 435    ctx.filePath = fnc.filePath;
 436    ctx.scopes = copyScope( fnc.scopes );
 437    ctx.scopes.push(scope);
 438
 439    execBlock(ctx, fnc.block);
 440
 441    const res = ctx.returnValue;
 442    ctx.returnValue = null;
 443
 444    ctx.fileName = oldFileName;
 445    ctx.filePath = oldFilePath;
 446    ctx.scopes = oldScopes;
 447
 448    return res;
 449}
 450
 451function execReturn(ctx, ast) {
 452    ctx.returnValue = exec(ctx, ast.value);
 453    return;
 454}
 455
 456function execDeclareSignal(ctx, ast) {
 457    const scope = ctx.scopes[ctx.scopes.length-1];
 458
 459    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
 460    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
 461
 462    const baseName = ctx.currentComponent ? ctx.currentComponent + "." + ast.name.name : ast.name.name;
 463
 464    const sizes=[];
 465    for (let i=0; i< ast.name.selectors.length; i++) {
 466        const size = exec(ctx, ast.name.selectors[i]);
 467        if (ctx.error) return;
 468
 469        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
 470        sizes.push( size.value.toJSNumber() );
 471    }
 472
 473    scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) {
 474        ctx.signals[fullName] = {
 475            fullName: fullName,
 476            direction: ast.declareType == "SIGNALIN" ? "IN" : (ast.declareType == "SIGNALOUT" ? "OUT" : ""),
 477            private: ast.private,
 478            component: ctx.currentComponent,
 479            equivalence: "",
 480            alias: [fullName]
 481        };
 482        ctx.components[ctx.currentComponent].signals.push(fullName);
 483        return {
 484            type: "SIGNAL",
 485            fullName: fullName,
 486        };
 487    });
 488    return {
 489        type: "VARIABLE",
 490        name: ast.name.name,
 491        selectors: []
 492    };
 493}
 494
 495function execDeclareVariable(ctx, ast) {
 496    const scope = ctx.scopes[ctx.scopes.length-1];
 497
 498    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid linear combination name");
 499    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
 500
 501    const sizes=[];
 502    for (let i=0; i< ast.name.selectors.length; i++) {
 503        const size = exec(ctx, ast.name.selectors[i]);
 504        if (ctx.error) return;
 505
 506        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
 507        sizes.push( size.value.toJSNumber() );
 508    }
 509
 510    scope[ast.name.name] = iterateSelectors(ctx, sizes, "", function() {
 511        return {
 512            type: "NUMBER",
 513            value: bigInt(0)
 514        };
 515    });
 516
 517    return {
 518        type: "VARIABLE",
 519        name: ast.name.name,
 520        selectors: []
 521    };
 522}
 523
 524function execVariable(ctx, ast) {
 525    let v;
 526    try {
 527        v = getScope(ctx, ast.name, ast.selectors);
 528    } catch(err) {
 529        console.log(JSON.stringify(ast, null,1));
 530    }
 531    if (ctx.error) return;
 532
 533    if (!v) return error(ctx, ast, "Variable not defined");
 534
 535    // If the signal has an assigned value (constant) just return the constant
 536    if ((v.type == "SIGNAL") && (ctx.signals[v.fullName].value)) {
 537        return {
 538            type: "NUMBER",
 539            value: ctx.signals[v.fullName].value
 540        };
 541    }
 542    let res;
 543    res=v;
 544    return res;
 545}
 546
 547function execPin(ctx, ast) {
 548    const component = getScope(ctx, ast.component.name, ast.component.selectors);
 549    if (!component) return error(ctx, ast.component, "Component does not exists: "+ast.component.name);
 550    if (ctx.error) return;
 551    let signalFullName = component.fullName + "." + ast.pin.name;
 552    for (let i=0; i< ast.pin.selectors.length; i++) {
 553        const sel = exec(ctx, ast.pin.selectors[i]);
 554        if (ctx.error) return;
 555
 556        if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
 557
 558        signalFullName += "[" + sel.value.toJSNumber() + "]";
 559    }
 560    if (!ctx.signals[signalFullName]) error(ctx, ast, "Signal not defined:" + signalFullName);
 561    return {
 562        type: "SIGNAL",
 563        fullName: signalFullName
 564    };
 565}
 566
 567function execFor(ctx, ast) {
 568
 569    ctx.scopes.push({});
 570    exec(ctx, ast.init);
 571    if (ctx.error) return;
 572
 573    let v = exec(ctx, ast.condition);
 574    if (ctx.error) return;
 575
 576    if (typeof v.value != "undefined") {
 577        while ((v.value.neq(0))&&(!ctx.returnValue)) {
 578            exec(ctx, ast.body);
 579            if (ctx.error) return;
 580
 581            exec(ctx, ast.step);
 582            if (ctx.error) return;
 583
 584            v = exec(ctx, ast.condition);
 585            if (ctx.error) return;
 586        }
 587    }
 588    ctx.scopes.pop();
 589}
 590
 591function execWhile(ctx, ast) {
 592    let v = exec(ctx, ast.condition);
 593    if (ctx.error) return;
 594
 595    if (typeof v.value != "undefined") {
 596        while ((v.value.neq(0))&&(!ctx.returnValue)) {
 597            exec(ctx, ast.body);
 598            if (ctx.error) return;
 599
 600            v = exec(ctx, ast.condition);
 601            if (ctx.error) return;
 602        }
 603    }
 604}
 605
 606function execIf(ctx, ast) {
 607    let v = exec(ctx, ast.condition);
 608    if (ctx.error) return;
 609
 610    if (typeof v.value != "undefined") {
 611        if ((v.value.neq(0))&&(!ctx.returnValue)) {
 612            exec(ctx, ast.then);
 613            if (ctx.error) return;
 614        } else {
 615            if (ast.else) {
 616                exec(ctx, ast.else);
 617                if (ctx.error) return;
 618            }
 619        }
 620    }
 621}
 622
 623
 624function execVarAssignement(ctx, ast) {
 625    let v;
 626    if (ast.values[0].type == "DECLARE") {
 627        v = exec(ctx, ast.values[0]);
 628        if (ctx.error) return;
 629    } else {
 630        v = ast.values[0];
 631    }
 632    const num = getScope(ctx, v.name, v.selectors);
 633    if (ctx.error) return;
 634
 635    if ((typeof(num) != "object")||(num == null)) return  error(ctx, ast, "Variable not defined");
 636
 637    if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
 638    if (ctx.error) return;
 639//    if (num.type == "SIGNAL") return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
 640
 641    const res = exec(ctx, ast.values[1]);
 642    if (ctx.error) return;
 643
 644    setScope(ctx, v.name, v.selectors, res);
 645
 646    return v;
 647}
 648
 649function execLt(ctx, ast) {
 650    const a = exec(ctx, ast.values[0]);
 651    if (ctx.error) return;
 652    if (a.type != "NUMBER") return { type: "NUMBER" };
 653    const b = exec(ctx, ast.values[1]);
 654    if (ctx.error) return;
 655    if (b.type != "NUMBER") return { type: "NUMBER" };
 656    if (!a.value || !b.value) return { type: "NUMBER" };
 657    return {
 658        type: "NUMBER",
 659        value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
 660    };
 661}
 662
 663function execGt(ctx, ast) {
 664    const a = exec(ctx, ast.values[0]);
 665    if (ctx.error) return;
 666    if (a.type != "NUMBER") return { type: "NUMBER" };
 667    const b = exec(ctx, ast.values[1]);
 668    if (ctx.error) return;
 669    if (b.type != "NUMBER") return { type: "NUMBER" };
 670    if (!a.value || !b.value) return { type: "NUMBER" };
 671    return {
 672        type: "NUMBER",
 673        value: a.value.gt(b.value) ? bigInt(1) : bigInt(0)
 674    };
 675}
 676
 677function execLte(ctx, ast) {
 678    const a = exec(ctx, ast.values[0]);
 679    if (ctx.error) return;
 680    if (a.type != "NUMBER") return { type: "NUMBER" };
 681    const b = exec(ctx, ast.values[1]);
 682    if (ctx.error) return;
 683    if (b.type != "NUMBER") return { type: "NUMBER" };
 684    if (!a.value || !b.value) return { type: "NUMBER" };
 685    return {
 686        type: "NUMBER",
 687        value: a.value.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0)
 688    };
 689}
 690
 691function execGte(ctx, ast) {
 692    const a = exec(ctx, ast.values[0]);
 693    if (ctx.error) return;
 694    if (a.type != "NUMBER") return { type: "NUMBER" };
 695    const b = exec(ctx, ast.values[1]);
 696    if (ctx.error) return;
 697    if (b.type != "NUMBER") return { type: "NUMBER" };
 698    if (!a.value || !b.value) return { type: "NUMBER" };
 699    return {
 700        type: "NUMBER",
 701        value: a.value.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0)
 702    };
 703}
 704
 705
 706function execEq(ctx, ast) {
 707    const a = exec(ctx, ast.values[0]);
 708    if (ctx.error) return;
 709    if (a.type != "NUMBER") return { type: "NUMBER" };
 710    const b = exec(ctx, ast.values[1]);
 711    if (ctx.error) return;
 712    if (b.type != "NUMBER") return { type: "NUMBER" };
 713    if (!a.value || !b.value) return { type: "NUMBER" };
 714    return {
 715        type: "NUMBER",
 716        value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
 717    };
 718}
 719
 720function execNeq(ctx, ast) {
 721    const a = exec(ctx, ast.values[0]);
 722    if (ctx.error) return;
 723    if (a.type != "NUMBER") return { type: "NUMBER" };
 724    const b = exec(ctx, ast.values[1]);
 725    if (ctx.error) return;
 726    if (b.type != "NUMBER") return { type: "NUMBER" };
 727    if (!a.value || !b.value) return { type: "NUMBER" };
 728    return {
 729        type: "NUMBER",
 730        value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
 731    };
 732}
 733
 734
 735function execBAnd(ctx, ast) {
 736    const a = exec(ctx, ast.values[0]);
 737    if (ctx.error) return;
 738    if (a.type != "NUMBER") return { type: "NUMBER" };
 739    const b = exec(ctx, ast.values[1]);
 740    if (ctx.error) return;
 741    if (b.type != "NUMBER") return { type: "NUMBER" };
 742    if (!a.value || !b.value) return { type: "NUMBER" };
 743    return {
 744        type: "NUMBER",
 745        value: a.value.and(b.value).and(__MASK__)
 746    };
 747}
 748
 749function execAnd(ctx, ast) {
 750    const a = exec(ctx, ast.values[0]);
 751    if (ctx.error) return;
 752    if (a.type != "NUMBER") return { type: "NUMBER" };
 753    const b = exec(ctx, ast.values[1]);
 754    if (ctx.error) return;
 755    if (b.type != "NUMBER") return { type: "NUMBER" };
 756    if (!a.value || !b.value) return { type: "NUMBER" };
 757    return {
 758        type: "NUMBER",
 759        value: (a.value.neq(0) && b.value.neq(0)) ? bigInt(1) : bigInt(0)
 760    };
 761}
 762
 763function execOr(ctx, ast) {
 764    const a = exec(ctx, ast.values[0]);
 765    if (ctx.error) return;
 766    if (a.type != "NUMBER") return { type: "NUMBER" };
 767    const b = exec(ctx, ast.values[1]);
 768    if (ctx.error) return;
 769    if (b.type != "NUMBER") return { type: "NUMBER" };
 770    if (!a.value || !b.value) return { type: "NUMBER" };
 771    return {
 772        type: "NUMBER",
 773        value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0)
 774    };
 775}
 776
 777function execShl(ctx, ast) {
 778    const a = exec(ctx, ast.values[0]);
 779    if (ctx.error) return;
 780    if (a.type != "NUMBER") return { type: "NUMBER" };
 781    const b = exec(ctx, ast.values[1]);
 782    if (ctx.error) return;
 783    if (b.type != "NUMBER") return { type: "NUMBER" };
 784    if (!a.value || !b.value) return { type: "NUMBER" };
 785    const v = b.value.greater(256) ? 256 : b.value.value;
 786    return {
 787        type: "NUMBER",
 788        value: a.value.shiftLeft(v).and(__MASK__)
 789    };
 790}
 791
 792function execShr(ctx, ast) {
 793    const a = exec(ctx, ast.values[0]);
 794    if (ctx.error) return;
 795    if (a.type != "NUMBER") return { type: "NUMBER" };
 796    const b = exec(ctx, ast.values[1]);
 797    if (ctx.error) return;
 798    if (b.type != "NUMBER") return { type: "NUMBER" };
 799    if (!a.value || !b.value) return { type: "NUMBER" };
 800    const v = b.value.greater(256) ? 256 : b.value.value;
 801    return {
 802        type: "NUMBER",
 803        value: a.value.shiftRight(v).and(__MASK__)
 804    };
 805}
 806
 807function execMod(ctx, ast) {
 808    const a = exec(ctx, ast.values[0]);
 809    if (ctx.error) return;
 810    if (a.type != "NUMBER") return { type: "NUMBER" };
 811    const b = exec(ctx, ast.values[1]);
 812    if (ctx.error) return;
 813    if (b.type != "NUMBER") return { type: "NUMBER" };
 814    if (!a.value || !b.value) return { type: "NUMBER" };
 815    return {
 816        type: "NUMBER",
 817        value: a.value.mod(b.value)
 818    };
 819}
 820
 821
 822function execExp(ctx, ast) {
 823    const a = exec(ctx, ast.values[0]);
 824    if (ctx.error) return;
 825    if (a.type != "NUMBER") return { type: "NUMBER" };
 826    const b = exec(ctx, ast.values[1]);
 827    if (ctx.error) return;
 828    if (b.type != "NUMBER") return { type: "NUMBER" };
 829    if (!a.value || !b.value) return { type: "NUMBER" };
 830    return {
 831        type: "NUMBER",
 832        value: a.value.modPow(b.value, __P__)
 833    };
 834}
 835
 836function execDiv(ctx, ast) {
 837    const a = exec(ctx, ast.values[0]);
 838    if (ctx.error) return;
 839    if (a.type != "NUMBER") return { type: "NUMBER" };
 840    const b = exec(ctx, ast.values[1]);
 841    if (ctx.error) return;
 842    if (b.type != "NUMBER") return { type: "NUMBER" };
 843    if (!a.value || !b.value) return { type: "NUMBER" };
 844    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 845    return {
 846        type: "NUMBER",
 847        value: a.value.times(b.value.modInv(__P__)).mod(__P__)
 848    };
 849}
 850
 851function execIDiv(ctx, ast) {
 852    const a = exec(ctx, ast.values[0]);
 853    if (ctx.error) return;
 854    if (a.type != "NUMBER") return { type: "NUMBER" };
 855    const b = exec(ctx, ast.values[1]);
 856    if (ctx.error) return;
 857    if (b.type != "NUMBER") return { type: "NUMBER" };
 858    if (!a.value || !b.value) return { type: "NUMBER" };
 859    if (b.value.isZero()) return error(ctx, ast, "Division by zero");
 860    return {
 861        type: "NUMBER",
 862        value: a.value.divide(b.value)
 863    };
 864}
 865
 866function execAdd(ctx, ast) {
 867    const a = exec(ctx, ast.values[0]);
 868    if (ctx.error) return;
 869    const b = exec(ctx, ast.values[1]);
 870    if (ctx.error) return;
 871
 872    const res = lc.add(a,b);
 873    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 874
 875    return res;
 876}
 877
 878function execSub(ctx, ast) {
 879    const a = exec(ctx, ast.values[0]);
 880    if (ctx.error) return;
 881    const b = exec(ctx, ast.values[1]);
 882    if (ctx.error) return;
 883
 884    const res = lc.sub(a,b);
 885    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 886
 887    return res;
 888}
 889
 890function execUMinus(ctx, ast) {
 891    const a = exec(ctx, ast.values[0]);
 892    if (ctx.error) return;
 893
 894    const res = lc.negate(a);
 895    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 896
 897    return res;
 898}
 899
 900function execMul(ctx, ast) {
 901    const a = exec(ctx, ast.values[0]);
 902    if (ctx.error) return;
 903    const b = exec(ctx, ast.values[1]);
 904    if (ctx.error) return;
 905
 906    const res = lc.mul(a,b);
 907    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
 908
 909    return res;
 910}
 911
 912
 913function execVarAddAssignement(ctx, ast) {
 914    const res = execAdd(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 execVarMulAssignement(ctx, ast) {
 920    const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
 921    if (ctx.error) return;
 922    return execVarAssignement(ctx, { values: [ast.values[0], res] });
 923}
 924
 925function execPlusPlusRight(ctx, ast) {
 926    const resBefore = exec(ctx, ast.values[0]);
 927    if (ctx.error) return;
 928    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
 929    if (ctx.error) return;
 930    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
 931    return resBefore;
 932}
 933
 934function execPlusPlusLeft(ctx, ast) {
 935    if (ctx.error) return;
 936    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
 937    if (ctx.error) return;
 938    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
 939    return resAfter;
 940}
 941
 942function execMinusMinusRight(ctx, ast) {
 943    const resBefore = exec(ctx, ast.values[0]);
 944    if (ctx.error) return;
 945    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
 946    if (ctx.error) return;
 947    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
 948    return resBefore;
 949}
 950
 951function execMinusMinusLeft(ctx, ast) {
 952    if (ctx.error) return;
 953    const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
 954    if (ctx.error) return;
 955    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
 956    return resAfter;
 957}
 958
 959function execTerCon(ctx, ast) {
 960    const cond = exec(ctx, ast.values[0]);
 961    if (ctx.error) return;
 962
 963    if (!cond.value) return { type: "NUMBER" };
 964
 965    if (cond.value.neq(0)) {
 966        return exec(ctx, ast.values[1]);
 967    } else {
 968        return exec(ctx, ast.values[2]);
 969    }
 970}
 971
 972function execSignalAssign(ctx, ast) {
 973    let vDest;
 974    if (ast.values[0].type == "DECLARE") {
 975        vDest = exec(ctx, ast.values[0]);
 976        if (ctx.error) return;
 977    } else {
 978        vDest = ast.values[0];
 979    }
 980
 981    let dst;
 982    if (vDest.type == "VARIABLE") {
 983        dst = getScope(ctx, vDest.name, vDest.selectors);
 984        if (ctx.error) return;
 985    } else if (vDest.type == "PIN") {
 986        dst = execPin(ctx, vDest);
 987        if (ctx.error) return;
 988    } else {
 989        error(ctx, ast, "Bad assignement");
 990    }
 991
 992    if (!dst) return  error(ctx, ast, "Signal not defined");
 993    if (dst.type != "SIGNAL") return  error(ctx, ast, "Signal assigned to a non signal");
 994
 995    let sDest=ctx.signals[dst.fullName];
 996    if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName);
 997    while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
 998
 999    if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
1000
1001    let src = exec(ctx, ast.values[1]);
1002    if (ctx.error) return;
1003
1004
1005    /*
1006    let vSrc;
1007    if (ast.values[1].type == "DECLARE") {
1008        vSrc = exec(ctx, ast.values[1]);
1009        if (ctx.error) return;
1010    } else {
1011        vSrc = ast.values[1];
1012    }
1013
1014    if (vSrc.type == "VARIABLE") {
1015        src = getScope(ctx, vSrc.name, vSrc.selectors);
1016        if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
1017        if (ctx.error) return;
1018    } else if (vSrc.type == "PIN") {
1019        src = execPin(ctx, vSrc);
1020    }
1021    */
1022
1023    let assignValue = true;
1024    if (src.type == "SIGNAL") {
1025        sDest.equivalence = src.fullName;
1026        sDest.alias = sDest.alias.concat(src.alias);
1027        while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
1028        assignValue = false;
1029    }
1030
1031    if (assignValue) {
1032        //        const resLC = exec(ctx, vSrc);
1033        if (ctx.error) return;
1034
1035        //        const v = lc.evaluate(ctx, resLC);
1036        const v = lc.evaluate(ctx, src);
1037
1038        if (v.value) {
1039            sDest.value = v.value;
1040        }
1041    }
1042
1043    return vDest;
1044}
1045
1046function execConstrain(ctx, ast) {
1047    const a = exec(ctx, ast.values[0]);
1048    if (ctx.error) return;
1049    const b = exec(ctx, ast.values[1]);
1050    if (ctx.error) return;
1051
1052    const res = lc.sub(a,b);
1053    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1054
1055    if (!lc.isZero(res)) {
1056        ctx.constraints.push(lc.toQEQ(res));
1057    }
1058
1059    return res;
1060}
1061
1062function execSignalAssignConstrain(ctx, ast) {
1063    const v = execSignalAssign(ctx,ast);
1064    if (ctx.error) return;
1065    execConstrain(ctx, ast);
1066    if (ctx.error) return;
1067    return v;
1068}
1069
1070function execInclude(ctx, ast) {
1071    const incFileName = path.resolve(ctx.filePath, ast.file);
1072    const incFilePath = path.dirname(incFileName);
1073
1074    ctx.includedFiles = ctx.includedFiles || [];
1075    if (ctx.includedFiles[incFileName]) return;
1076
1077    ctx.includedFiles[incFileName] = true;
1078
1079    const src = fs.readFileSync(incFileName, "utf8");
1080
1081    if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
1082
1083    const incAst = parser.parse(src);
1084
1085    const oldFilePath = ctx.filePath;
1086    const oldFileName = ctx.fileName;
1087    ctx.filePath = incFilePath;
1088    ctx.fileName = incFileName;
1089
1090    exec(ctx, incAst);
1091
1092    ast.block = incAst;
1093
1094    ctx.filePath = oldFilePath;
1095    ctx.fileName = oldFileName;
1096}
1097
1098function execArray(ctx, ast) {
1099    const res = [];
1100
1101    for (let i=0; i<ast.values.length; i++) {
1102        res.push(exec(ctx, ast.values[i]));
1103    }
1104
1105    return res;
1106}
1107
1108function copyScope(scope) {
1109    var scopesClone = [];
1110    for (let i=0; i<scope.length; i++) {
1111        scopesClone.push(scope[i]);
1112    }
1113    return scopesClone;
1114}
1115