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