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