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