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")&&(ast.op == "=")) return error(ctx, ast, "Cannot assign to a signal with `=` use <-- or <== ops");
713 if ((["NUMBER", "COMPONENT"].indexOf(num.type) >= 0 )&&(ast.op != "=")) return error(ctx, ast, `Cannot assign to a var with ${ast.op}. use = op`);
714
715 const res = exec(ctx, ast.values[1]);
716 if (ctx.error) return;
717
718 Object.assign(num, res);
719// setScope(ctx, v.name, v.selectors, res);
720
721 return v;
722}
723
724function execLt(ctx, ast) {
725 const a = exec(ctx, ast.values[0]);
726 if (ctx.error) return;
727 if (a.type != "NUMBER") return { type: "NUMBER" };
728 const b = exec(ctx, ast.values[1]);
729 if (ctx.error) return;
730 if (b.type != "NUMBER") return { type: "NUMBER" };
731 if (!a.value || !b.value) return { type: "NUMBER" };
732 return {
733 type: "NUMBER",
734 value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
735 };
736}
737
738function execGt(ctx, ast) {
739 const a = exec(ctx, ast.values[0]);
740 if (ctx.error) return;
741 if (a.type != "NUMBER") return { type: "NUMBER" };
742 const b = exec(ctx, ast.values[1]);
743 if (ctx.error) return;
744 if (b.type != "NUMBER") return { type: "NUMBER" };
745 if (!a.value || !b.value) return { type: "NUMBER" };
746 return {
747 type: "NUMBER",
748 value: a.value.gt(b.value) ? bigInt(1) : bigInt(0)
749 };
750}
751
752function execLte(ctx, ast) {
753 const a = exec(ctx, ast.values[0]);
754 if (ctx.error) return;
755 if (a.type != "NUMBER") return { type: "NUMBER" };
756 const b = exec(ctx, ast.values[1]);
757 if (ctx.error) return;
758 if (b.type != "NUMBER") return { type: "NUMBER" };
759 if (!a.value || !b.value) return { type: "NUMBER" };
760 return {
761 type: "NUMBER",
762 value: a.value.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0)
763 };
764}
765
766function execGte(ctx, ast) {
767 const a = exec(ctx, ast.values[0]);
768 if (ctx.error) return;
769 if (a.type != "NUMBER") return { type: "NUMBER" };
770 const b = exec(ctx, ast.values[1]);
771 if (ctx.error) return;
772 if (b.type != "NUMBER") return { type: "NUMBER" };
773 if (!a.value || !b.value) return { type: "NUMBER" };
774 return {
775 type: "NUMBER",
776 value: a.value.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0)
777 };
778}
779
780
781function execEq(ctx, ast) {
782 const a = exec(ctx, ast.values[0]);
783 if (ctx.error) return;
784 if (a.type != "NUMBER") return { type: "NUMBER" };
785 const b = exec(ctx, ast.values[1]);
786 if (ctx.error) return;
787 if (b.type != "NUMBER") return { type: "NUMBER" };
788 if (!a.value || !b.value) return { type: "NUMBER" };
789 return {
790 type: "NUMBER",
791 value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
792 };
793}
794
795function execNeq(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.eq(b.value) ? bigInt(0) : bigInt(1)
806 };
807}
808
809
810function execBAnd(ctx, ast) {
811 const a = exec(ctx, ast.values[0]);
812 if (ctx.error) return;
813 if (a.type != "NUMBER") return { type: "NUMBER" };
814 const b = exec(ctx, ast.values[1]);
815 if (ctx.error) return;
816 if (b.type != "NUMBER") return { type: "NUMBER" };
817 if (!a.value || !b.value) return { type: "NUMBER" };
818 return {
819 type: "NUMBER",
820 value: a.value.and(b.value).and(__MASK__)
821 };
822}
823
824function execAnd(ctx, ast) {
825 const a = exec(ctx, ast.values[0]);
826 if (ctx.error) return;
827 if (a.type != "NUMBER") return { type: "NUMBER" };
828 const b = exec(ctx, ast.values[1]);
829 if (ctx.error) return;
830 if (b.type != "NUMBER") return { type: "NUMBER" };
831 if (!a.value || !b.value) return { type: "NUMBER" };
832 return {
833 type: "NUMBER",
834 value: (a.value.neq(0) && b.value.neq(0)) ? bigInt(1) : bigInt(0)
835 };
836}
837
838function execOr(ctx, ast) {
839 const a = exec(ctx, ast.values[0]);
840 if (ctx.error) return;
841 if (a.type != "NUMBER") return { type: "NUMBER" };
842 const b = exec(ctx, ast.values[1]);
843 if (ctx.error) return;
844 if (b.type != "NUMBER") return { type: "NUMBER" };
845 if (!a.value || !b.value) return { type: "NUMBER" };
846 return {
847 type: "NUMBER",
848 value: (a.value.neq(0) || b.value.neq(0)) ? bigInt(1) : bigInt(0)
849 };
850}
851
852function execShl(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 const v = b.value.greater(256) ? 256 : b.value.value;
861 return {
862 type: "NUMBER",
863 value: a.value.shiftLeft(v).and(__MASK__)
864 };
865}
866
867function execShr(ctx, ast) {
868 const a = exec(ctx, ast.values[0]);
869 if (ctx.error) return;
870 if (a.type != "NUMBER") return { type: "NUMBER" };
871 const b = exec(ctx, ast.values[1]);
872 if (ctx.error) return;
873 if (b.type != "NUMBER") return { type: "NUMBER" };
874 if (!a.value || !b.value) return { type: "NUMBER" };
875 const v = b.value.greater(256) ? 256 : b.value.value;
876 return {
877 type: "NUMBER",
878 value: a.value.shiftRight(v).and(__MASK__)
879 };
880}
881
882function execMod(ctx, ast) {
883 const a = exec(ctx, ast.values[0]);
884 if (ctx.error) return;
885 if (a.type != "NUMBER") return { type: "NUMBER" };
886 const b = exec(ctx, ast.values[1]);
887 if (ctx.error) return;
888 if (b.type != "NUMBER") return { type: "NUMBER" };
889 if (!a.value || !b.value) return { type: "NUMBER" };
890 return {
891 type: "NUMBER",
892 value: a.value.mod(b.value)
893 };
894}
895
896
897function execExp(ctx, ast) {
898 const a = exec(ctx, ast.values[0]);
899 if (ctx.error) return;
900 if (a.type != "NUMBER") return { type: "NUMBER" };
901 const b = exec(ctx, ast.values[1]);
902 if (ctx.error) return;
903 if (b.type != "NUMBER") return { type: "NUMBER" };
904 if (!a.value || !b.value) return { type: "NUMBER" };
905 return {
906 type: "NUMBER",
907 value: a.value.modPow(b.value, __P__)
908 };
909}
910
911function execDiv(ctx, ast) {
912 const a = exec(ctx, ast.values[0]);
913 if (ctx.error) return;
914 if (a.type != "NUMBER") return { type: "NUMBER" };
915 const b = exec(ctx, ast.values[1]);
916 if (ctx.error) return;
917 if (b.type != "NUMBER") return { type: "NUMBER" };
918 if (!a.value || !b.value) return { type: "NUMBER" };
919 if (b.value.isZero()) return error(ctx, ast, "Division by zero");
920 return {
921 type: "NUMBER",
922 value: a.value.times(b.value.modInv(__P__)).mod(__P__)
923 };
924}
925
926function execIDiv(ctx, ast) {
927 const a = exec(ctx, ast.values[0]);
928 if (ctx.error) return;
929 if (a.type != "NUMBER") return { type: "NUMBER" };
930 const b = exec(ctx, ast.values[1]);
931 if (ctx.error) return;
932 if (b.type != "NUMBER") return { type: "NUMBER" };
933 if (!a.value || !b.value) return { type: "NUMBER" };
934 if (b.value.isZero()) return error(ctx, ast, "Division by zero");
935 return {
936 type: "NUMBER",
937 value: a.value.divide(b.value)
938 };
939}
940
941function execAdd(ctx, ast) {
942 const a = exec(ctx, ast.values[0]);
943 if (ctx.error) return;
944 const b = exec(ctx, ast.values[1]);
945 if (ctx.error) return;
946
947 const res = lc.add(a,b);
948 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
949
950 return res;
951}
952
953function execSub(ctx, ast) {
954 const a = exec(ctx, ast.values[0]);
955 if (ctx.error) return;
956 const b = exec(ctx, ast.values[1]);
957 if (ctx.error) return;
958
959 const res = lc.sub(a,b);
960 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
961
962 return res;
963}
964
965function execUMinus(ctx, ast) {
966 const a = exec(ctx, ast.values[0]);
967 if (ctx.error) return;
968
969 const res = lc.negate(a);
970 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
971
972 return res;
973}
974
975function execMul(ctx, ast) {
976 const a = exec(ctx, ast.values[0]);
977 if (ctx.error) return;
978 const b = exec(ctx, ast.values[1]);
979 if (ctx.error) return;
980
981 const res = lc.mul(a,b);
982 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
983
984 return res;
985}
986
987
988function execVarAddAssignement(ctx, ast) {
989 const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
990 if (ctx.error) return;
991 return execVarAssignement(ctx, { op:"=", values: [ast.values[0], res] });
992}
993
994function execVarMulAssignement(ctx, ast) {
995 const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
996 if (ctx.error) return;
997 return execVarAssignement(ctx, { op:"=", values: [ast.values[0], res] });
998}
999
1000function execPlusPlusRight(ctx, ast) {
1001 const resBefore = exec(ctx, ast.values[0]);
1002 if (ctx.error) return;
1003 const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1004 if (ctx.error) return;
1005 execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1006 return resBefore;
1007}
1008
1009function execPlusPlusLeft(ctx, ast) {
1010 if (ctx.error) return;
1011 const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1012 if (ctx.error) return;
1013 execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1014 return resAfter;
1015}
1016
1017function execMinusMinusRight(ctx, ast) {
1018 const resBefore = exec(ctx, ast.values[0]);
1019 if (ctx.error) return;
1020 const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1021 if (ctx.error) return;
1022 execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1023 return resBefore;
1024}
1025
1026function execMinusMinusLeft(ctx, ast) {
1027 if (ctx.error) return;
1028 const resAfter = execSub(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
1029 if (ctx.error) return;
1030 execVarAssignement(ctx, { op:"=", values: [ast.values[0], resAfter] });
1031 return resAfter;
1032}
1033
1034function execTerCon(ctx, ast) {
1035 const cond = exec(ctx, ast.values[0]);
1036 if (ctx.error) return;
1037
1038 if (!cond.value) return { type: "NUMBER" };
1039
1040 if (cond.value.neq(0)) {
1041 return exec(ctx, ast.values[1]);
1042 } else {
1043 return exec(ctx, ast.values[2]);
1044 }
1045}
1046
1047function execSignalAssign(ctx, ast) {
1048 let vDest;
1049 if (ast.values[0].type == "DECLARE") {
1050 vDest = exec(ctx, ast.values[0]);
1051 if (ctx.error) return;
1052 } else {
1053 vDest = ast.values[0];
1054 }
1055
1056 let dst;
1057 if (vDest.type == "VARIABLE") {
1058 dst = getScope(ctx, vDest.name, vDest.selectors);
1059 if (ctx.error) return;
1060 } else if (vDest.type == "PIN") {
1061 dst = execPin(ctx, vDest);
1062 if (ctx.error) return;
1063 } else {
1064 error(ctx, ast, "Bad assignement");
1065 }
1066
1067 if (!dst) return error(ctx, ast, "Signal not defined");
1068 if (dst.type != "SIGNAL") return error(ctx, ast, "Signal assigned to a non signal");
1069
1070 let sDest=ctx.signals[dst.sIdx];
1071 if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.sIdx);
1072
1073 let isOut = (sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT);
1074 while (sDest.e>=0) {
1075 sDest=ctx.signals[sDest.e];
1076 isOut = isOut || ((sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT));
1077 }
1078
1079 if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
1080
1081 let src = exec(ctx, ast.values[1]);
1082 if (ctx.error) return;
1083
1084
1085 /*
1086 let vSrc;
1087 if (ast.values[1].type == "DECLARE") {
1088 vSrc = exec(ctx, ast.values[1]);
1089 if (ctx.error) return;
1090 } else {
1091 vSrc = ast.values[1];
1092 }
1093
1094 if (vSrc.type == "VARIABLE") {
1095 src = getScope(ctx, vSrc.name, vSrc.selectors);
1096 if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
1097 if (ctx.error) return;
1098 } else if (vSrc.type == "PIN") {
1099 src = execPin(ctx, vSrc);
1100 }
1101 */
1102
1103 let assignValue = true;
1104 if (src.type == "SIGNAL") {
1105 let sSrc = ctx.signals[src.sIdx];
1106 let isIn = (sSrc.o & ctx.main)&&(sSrc.o & ctx.IN);
1107 while (sSrc.e>=0) {
1108 sSrc=ctx.signals[sSrc.e];
1109 isIn = isIn || ((sSrc.o & ctx.main)&&(sSrc.o & ctx.IN));
1110 }
1111
1112 // Skip if an out is assigned directly to an input.
1113 if ((!isIn)||(!isOut)) {
1114 sDest.e = src.sIdx;
1115 while (sDest.e >= 0) sDest=ctx.signals[sDest.e];
1116 assignValue = false;
1117 }
1118 }
1119
1120 if (assignValue) {
1121 // const resLC = exec(ctx, vSrc);
1122 if (ctx.error) return;
1123
1124 // const v = lc.evaluate(ctx, resLC);
1125 const v = lc.evaluate(ctx, src);
1126
1127 if (v.value) {
1128 sDest.v = v.value;
1129 }
1130 }
1131
1132 return vDest;
1133}
1134
1135function execConstrain(ctx, ast) {
1136 ast.fileName = ctx.fileName;
1137 ast.filePath = ctx.filePath;
1138 const a = exec(ctx, ast.values[0]);
1139 if (ctx.error) return;
1140 const b = exec(ctx, ast.values[1]);
1141 if (ctx.error) return;
1142
1143 const res = lc.sub(a,b);
1144 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1145
1146 if (!lc.isZero(res)) {
1147 ctx.constraints.push(lc.toQEQ(res));
1148 }
1149
1150 if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
1151
1152 return res;
1153}
1154
1155function execSignalAssignConstrain(ctx, ast) {
1156 const v = execSignalAssign(ctx,ast);
1157 if (ctx.error) return;
1158 execConstrain(ctx, ast);
1159 if (ctx.error) return;
1160 return v;
1161}
1162
1163function execInclude(ctx, ast) {
1164 const incFileName = path.resolve(ctx.filePath, ast.file);
1165 const incFilePath = path.dirname(incFileName);
1166
1167 ctx.includedFiles = ctx.includedFiles || [];
1168 if (ctx.includedFiles[incFileName]) return;
1169
1170
1171 const src = fs.readFileSync(incFileName, "utf8");
1172
1173 ctx.includedFiles[incFileName] = src.split("\n");
1174
1175 if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
1176
1177 const incAst = parser.parse(src);
1178
1179 const oldFilePath = ctx.filePath;
1180 const oldFileName = ctx.fileName;
1181 ctx.filePath = incFilePath;
1182 ctx.fileName = incFileName;
1183
1184 exec(ctx, incAst);
1185
1186 ast.block = incAst;
1187
1188 ctx.filePath = oldFilePath;
1189 ctx.fileName = oldFileName;
1190}
1191
1192function execArray(ctx, ast) {
1193 const res = [];
1194
1195 for (let i=0; i<ast.values.length; i++) {
1196 res.push(exec(ctx, ast.values[i]));
1197 }
1198
1199 return res;
1200}
1201
1202function copyScope(scope) {
1203 var scopesClone = [];
1204 for (let i=0; i<scope.length; i++) {
1205 scopesClone.push(scope[i]);
1206 }
1207 return scopesClone;
1208}
1209