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