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