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