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