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            private: ast.private,
423            component: ctx.currentComponent,
424            equivalence: "",
425            alias: [fullName]
426        };
427        ctx.components[ctx.currentComponent].signals.push(fullName);
428        return {
429            type: "SIGNAL",
430            fullName: fullName,
431        };
432    });
433    return {
434        type: "VARIABLE",
435        name: ast.name.name,
436        selectors: []
437    };
438}
439
440function execDeclareVariable(ctx, ast) {
441    const scope = ctx.scopes[ctx.scopes.length-1];
442
443    if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid linear combination name");
444    if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
445
446    const sizes=[];
447    for (let i=0; i< ast.name.selectors.length; i++) {
448        const size = exec(ctx, ast.name.selectors[i]);
449        if (ctx.error) return;
450
451        if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
452        sizes.push( size.value.toJSNumber() );
453    }
454
455    scope[ast.name.name] = iterateSelectors(ctx, sizes, "", function() {
456        return {
457            type: "NUMBER",
458            value: bigInt(0)
459        };
460    });
461
462    return {
463        type: "VARIABLE",
464        name: ast.name.name,
465        selectors: []
466    };
467}
468
469function execVariable(ctx, ast) {
470    const v = getScope(ctx, ast.name, ast.selectors);
471    if (ctx.error) return;
472
473    if (!v) return error(ctx, ast, "Variable not defined");
474    let res;
475    res=v;
476    return res;
477}
478
479function execPin(ctx, ast) {
480    const component = getScope(ctx, ast.component.name, ast.component.selectors);
481    if (!component) return error(ctx, ast.component, "Component does not exists: "+ast.component.name);
482    if (ctx.error) return;
483    let signalFullName = component.fullName + "." + ast.pin.name;
484    for (let i=0; i< ast.pin.selectors.length; i++) {
485        const sel = exec(ctx, ast.pin.selectors[i]);
486        if (ctx.error) return;
487
488        if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
489
490        signalFullName += "[" + sel.value.toJSNumber() + "]";
491    }
492    if (!ctx.signals[signalFullName]) error(ctx, ast, "Signal not defined:" + signalFullName);
493    return {
494        type: "SIGNAL",
495        fullName: signalFullName
496    };
497}
498
499function execFor(ctx, ast) {
500    exec(ctx, ast.init);
501    if (ctx.error) return;
502
503    let v = exec(ctx, ast.condition);
504    if (ctx.error) return;
505
506    while ((v.value.neq(0))&&(!ctx.returnValue)) {
507        exec(ctx, ast.body);
508        if (ctx.error) return;
509
510        exec(ctx, ast.step);
511        if (ctx.error) return;
512
513        v = exec(ctx, ast.condition);
514        if (ctx.error) return;
515    }
516}
517
518function execWhile(ctx, ast) {
519    let v = exec(ctx, ast.condition);
520    if (ctx.error) return;
521
522    while ((v.value.neq(0))&&(!ctx.returnValue)) {
523        exec(ctx, ast.body);
524        if (ctx.error) return;
525
526        v = exec(ctx, ast.condition);
527        if (ctx.error) return;
528    }
529}
530
531
532function execVarAssignement(ctx, ast) {
533    let v;
534    if (ast.values[0].type == "DECLARE") {
535        v = exec(ctx, ast.values[0]);
536        if (ctx.error) return;
537    } else {
538        v = ast.values[0];
539    }
540    const num = getScope(ctx, v.name, v.selectors);
541    if (ctx.error) return;
542
543    if (typeof(num) != "object") return  error(ctx, ast, "Variable not defined");
544
545    if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
546
547    const res = exec(ctx, ast.values[1]);
548    if (ctx.error) return;
549
550    setScope(ctx, v.name, v.selectors, res);
551
552    return v;
553}
554
555function execLt(ctx, ast) {
556    const a = exec(ctx, ast.values[0]);
557    if (ctx.error) return;
558    if (a.type != "NUMBER") return { type: "NUMBER" };
559    const b = exec(ctx, ast.values[1]);
560    if (ctx.error) return;
561    if (b.type != "NUMBER") return { type: "NUMBER" };
562    if (!a.value || !b.value) return { type: "NUMBER" };
563    return {
564        type: "NUMBER",
565        value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
566    };
567}
568
569function execEq(ctx, ast) {
570    const a = exec(ctx, ast.values[0]);
571    if (ctx.error) return;
572    if (a.type != "NUMBER") return { type: "NUMBER" };
573    const b = exec(ctx, ast.values[1]);
574    if (ctx.error) return;
575    if (b.type != "NUMBER") return { type: "NUMBER" };
576    if (!a.value || !b.value) return { type: "NUMBER" };
577    return {
578        type: "NUMBER",
579        value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
580    };
581}
582
583
584function execBAnd(ctx, ast) {
585    const a = exec(ctx, ast.values[0]);
586    if (ctx.error) return;
587    if (a.type != "NUMBER") return { type: "NUMBER" };
588    const b = exec(ctx, ast.values[1]);
589    if (ctx.error) return;
590    if (b.type != "NUMBER") return { type: "NUMBER" };
591    if (!a.value || !b.value) return { type: "NUMBER" };
592    return {
593        type: "NUMBER",
594        value: a.value.and(b.value).and(__MASK__)
595    };
596}
597
598function execShl(ctx, ast) {
599    const a = exec(ctx, ast.values[0]);
600    if (ctx.error) return;
601    if (a.type != "NUMBER") return { type: "NUMBER" };
602    const b = exec(ctx, ast.values[1]);
603    if (ctx.error) return;
604    if (b.type != "NUMBER") return { type: "NUMBER" };
605    if (!a.value || !b.value) return { type: "NUMBER" };
606    const v = b.value.greater(256) ? 256 : b.value.value;
607    return {
608        type: "NUMBER",
609        value: a.value.shiftLeft(v).and(__MASK__)
610    };
611}
612
613function execShr(ctx, ast) {
614    const a = exec(ctx, ast.values[0]);
615    if (ctx.error) return;
616    if (a.type != "NUMBER") return { type: "NUMBER" };
617    const b = exec(ctx, ast.values[1]);
618    if (ctx.error) return;
619    if (b.type != "NUMBER") return { type: "NUMBER" };
620    if (!a.value || !b.value) return { type: "NUMBER" };
621    const v = b.value.greater(256) ? 256 : b.value.value;
622    return {
623        type: "NUMBER",
624        value: a.value.shiftRight(v).and(__MASK__)
625    };
626}
627
628function execExp(ctx, ast) {
629    const a = exec(ctx, ast.values[0]);
630    if (ctx.error) return;
631    if (a.type != "NUMBER") return { type: "NUMBER" };
632    const b = exec(ctx, ast.values[1]);
633    if (ctx.error) return;
634    if (b.type != "NUMBER") return { type: "NUMBER" };
635    if (!a.value || !b.value) return { type: "NUMBER" };
636    return {
637        type: "NUMBER",
638        value: a.value.modPow(b.value, __P__)
639    };
640}
641
642function execAdd(ctx, ast) {
643    const a = exec(ctx, ast.values[0]);
644    if (ctx.error) return;
645    const b = exec(ctx, ast.values[1]);
646    if (ctx.error) return;
647
648    const res = lc.add(a,b);
649    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
650
651    return res;
652}
653
654function execSub(ctx, ast) {
655    const a = exec(ctx, ast.values[0]);
656    if (ctx.error) return;
657    const b = exec(ctx, ast.values[1]);
658    if (ctx.error) return;
659
660    const res = lc.sub(a,b);
661    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
662
663    return res;
664}
665
666function execUMinus(ctx, ast) {
667    const a = exec(ctx, ast.values[0]);
668    if (ctx.error) return;
669
670    const res = lc.negate(a);
671    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
672
673    return res;
674}
675
676function execMul(ctx, ast) {
677    const a = exec(ctx, ast.values[0]);
678    if (ctx.error) return;
679    const b = exec(ctx, ast.values[1]);
680    if (ctx.error) return;
681
682    const res = lc.mul(a,b);
683    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
684
685    return res;
686}
687
688function execVarAddAssignement(ctx, ast) {
689    const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
690    if (ctx.error) return;
691    return execVarAssignement(ctx, { values: [ast.values[0], res] });
692}
693
694function execVarMulAssignement(ctx, ast) {
695    const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
696    if (ctx.error) return;
697    return execVarAssignement(ctx, { values: [ast.values[0], res] });
698}
699
700function execPlusPlusRight(ctx, ast) {
701    const resBefore = exec(ctx, ast.values[0]);
702    if (ctx.error) return;
703    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
704    if (ctx.error) return;
705    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
706    return resBefore;
707}
708
709function execPlusPlusLeft(ctx, ast) {
710    if (ctx.error) return;
711    const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
712    if (ctx.error) return;
713    execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
714    return resAfter;
715}
716
717function execTerCon(ctx, ast) {
718    const cond = exec(ctx, ast.values[0]);
719    if (ctx.error) return;
720
721    if (!cond.value) return { type: "NUMBER" };
722
723    if (cond.value.neq(0)) {
724        return exec(ctx, ast.values[1]);
725    } else {
726        return exec(ctx, ast.values[2]);
727    }
728}
729
730function execSignalAssign(ctx, ast) {
731    let vDest;
732    if (ast.values[0].type == "DECLARE") {
733        vDest = exec(ctx, ast.values[0]);
734        if (ctx.error) return;
735    } else {
736        vDest = ast.values[0];
737    }
738
739    let dst;
740    if (vDest.type == "VARIABLE") {
741        dst = getScope(ctx, vDest.name, vDest.selectors);
742        if (ctx.error) return;
743    } else if (vDest.type == "PIN") {
744        dst = execPin(ctx, vDest);
745        if (ctx.error) return;
746    } else {
747        error(ctx, ast, "Bad assignement");
748    }
749
750    if (!dst) return  error(ctx, ast, "Signal not defined");
751    if (dst.type != "SIGNAL") return  error(ctx, ast, "Signal assigned to a non signal");
752
753    let sDest=ctx.signals[dst.fullName];
754    if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName);
755    while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
756
757    if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
758
759    let src = exec(ctx, ast.values[1]);
760    if (ctx.error) return;
761
762
763    /*
764    let vSrc;
765    if (ast.values[1].type == "DECLARE") {
766        vSrc = exec(ctx, ast.values[1]);
767        if (ctx.error) return;
768    } else {
769        vSrc = ast.values[1];
770    }
771
772    if (vSrc.type == "VARIABLE") {
773        src = getScope(ctx, vSrc.name, vSrc.selectors);
774        if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
775        if (ctx.error) return;
776    } else if (vSrc.type == "PIN") {
777        src = execPin(ctx, vSrc);
778    }
779    */
780
781    let assignValue = true;
782    if (src.type == "SIGNAL") {
783        sDest.equivalence = src.fullName;
784        sDest.alias = sDest.alias.concat(src.alias);
785        while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
786        assignValue = false;
787    }
788
789    if (assignValue) {
790        //        const resLC = exec(ctx, vSrc);
791        if (ctx.error) return;
792
793        //        const v = lc.evaluate(ctx, resLC);
794        const v = lc.evaluate(ctx, src);
795
796        if (v.value) {
797            sDest.value = v.value;
798        }
799    }
800
801    return vDest;
802}
803
804function execConstrain(ctx, ast) {
805    const a = exec(ctx, ast.values[0]);
806    if (ctx.error) return;
807    const b = exec(ctx, ast.values[1]);
808    if (ctx.error) return;
809
810    const res = lc.sub(a,b);
811    if (res.type == "ERROR") return error(ctx, ast, res.errStr);
812
813    if (!lc.isZero(res)) {
814        ctx.constrains.push(lc.toQEQ(res));
815    }
816
817    return res;
818}
819
820function execSignalAssignConstrain(ctx, ast) {
821    const v = execSignalAssign(ctx,ast);
822    if (ctx.error) return;
823    execConstrain(ctx, ast);
824    if (ctx.error) return;
825    return v;
826}
827
828function execInclude(ctx, ast) {
829    const incFileName = path.resolve(ctx.filePath, ast.file);
830    const incFilePath = path.dirname(incFileName);
831
832    ctx.includedFiles = ctx.includedFiles || [];
833    if (ctx.includedFiles[incFileName]) return;
834
835    ctx.includedFiles[incFileName] = true;
836
837    const src = fs.readFileSync(incFileName, "utf8");
838
839    if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
840
841    const incAst = parser.parse(src);
842
843    const oldFilePath = ctx.filePath;
844    const oldFileName = ctx.fileName;
845    ctx.filePath = incFilePath;
846    ctx.fileName = incFileName;
847
848    exec(ctx, incAst);
849
850    ast.block = incAst;
851
852    ctx.filePath = oldFilePath;
853    ctx.fileName = oldFileName;
854}
855
856function execArray(ctx, ast) {
857    const res = [];
858
859    for (let i=0; i<ast.values.length; i++) {
860        res.push(exec(ctx, ast.values[i]));
861    }
862
863    return res;
864}
865
866function copyScope(scope) {
867    var scopesClone = [];
868    for (let i=0; i<scope.length; i++) {
869        scopesClone.push(scope[i]);
870    }
871    return scopesClone;
872}
873