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