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