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