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