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