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