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