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