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