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