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