circom/src/exec.js
src/exec.jsRaw
1/*
2 Copyright 2018 0KIMS association.
3
4 This file is part of circom (Zero Knowledge Circuit Compiler).
5
6 circom is a free software: you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 circom is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
14 License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with circom. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20const path = require("path");
21const fs = require("fs");
22
23const bigInt = require("big-integer");
24const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
25const __MASK__ = new bigInt(2).pow(253).minus(1);
26
27const lc = require("./lcalgebra");
28const parser = require("../parser/jaz.js").parser;
29
30/* TODO: Add lines information
31
32function setLines(dst, first, last) {
33 last = last || first;
34 dst.first_line = first.first_line;
35 dst.first_column = first.first_column;
36 dst.last_line = last.last_line;
37 dst.last_column = last.last_column;
38}
39*/
40
41module.exports = exec;
42
43
44function exec(ctx, ast) {
45 if (!ast) {
46 return error(ctx, ast, "Null AST");
47 }
48 if ((ast.type == "NUMBER") || (ast.type == "LINEARCOMBINATION") || (ast.type =="SIGNAL") || (ast.type == "QEQ")) {
49 return ast;
50 } else if (ast.type == "VARIABLE") {
51 return execVariable(ctx, ast);
52 } else if (ast.type == "PIN") {
53 return execPin(ctx, ast);
54 } else if (ast.type == "OP") {
55 if (ast.op == "=") {
56 return execVarAssignement(ctx, ast);
57 } else if (ast.op == "<--") {
58 return execSignalAssign(ctx, ast);
59 } else if (ast.op == "<==") {
60 return execSignalAssignConstrain(ctx, ast);
61 } else if (ast.op == "===") {
62 return execConstrain(ctx, ast);
63 } else if (ast.op == "+=") {
64 return execVarAddAssignement(ctx, ast);
65 } else if (ast.op == "*=") {
66 return execVarMulAssignement(ctx, ast);
67 } else if (ast.op == "+") {
68 return execAdd(ctx, ast);
69 } else if (ast.op == "-") {
70 return execSub(ctx, ast);
71 } else if (ast.op == "UMINUS") {
72 return execUMinus(ctx, ast);
73 } else if (ast.op == "*") {
74 return execMul(ctx, ast);
75 } else if (ast.op == "%") {
76 return execMod(ctx, ast);
77 } else if (ast.op == "PLUSPLUSRIGHT") {
78 return execPlusPlusRight(ctx, ast);
79 } else if (ast.op == "PLUSPLUSLEFT") {
80 return execPlusPlusLeft(ctx, ast);
81 } else if (ast.op == "/") {
82 return execDiv(ctx, ast);
83 } else if (ast.op == "\\") {
84 return execIDiv(ctx, ast);
85 } else if (ast.op == "**") {
86 return execExp(ctx, ast);
87 } else if (ast.op == "&") {
88 return execBAnd(ctx, ast);
89 } else if (ast.op == "&&") {
90 return execAnd(ctx, ast);
91 } else if (ast.op == "||") {
92 return execOr(ctx, ast);
93 } else if (ast.op == "<<") {
94 return execShl(ctx, ast);
95 } else if (ast.op == ">>") {
96 return execShr(ctx, ast);
97 } else if (ast.op == "<") {
98 return execLt(ctx, ast);
99 } else if (ast.op == ">") {
100 return execGt(ctx, ast);
101 } else if (ast.op == "<=") {
102 return execLte(ctx, ast);
103 } else if (ast.op == ">=") {
104 return execGte(ctx, ast);
105 } else if (ast.op == "==") {
106 return execEq(ctx, ast);
107 } else if (ast.op == "!=") {
108 return execNeq(ctx, ast);
109 } else if (ast.op == "?") {
110 return execTerCon(ctx, ast);
111 } else {
112 error(ctx, ast, "Invalid operation: " + ast.op);
113 }
114 } else if (ast.type == "DECLARE") {
115 if (ast.declareType == "COMPONENT") {
116 return execDeclareComponent(ctx, ast);
117 } else if ((ast.declareType == "SIGNALIN")||
118 (ast.declareType == "SIGNALOUT")||
119 (ast.declareType == "SIGNAL")) {
120 return execDeclareSignal(ctx, ast);
121 } else if (ast.declareType == "VARIABLE") {
122 return execDeclareVariable(ctx, ast);
123 } else {
124 error(ctx, ast, "Invalid declaration: " + ast.declareType);
125 }
126 } else if (ast.type == "FUNCTIONCALL") {
127 return execFunctionCall(ctx, ast);
128 } else if (ast.type == "BLOCK") {
129 return execBlock(ctx, ast);
130 } else if (ast.type == "FOR") {
131 return execFor(ctx, ast);
132 } else if (ast.type == "WHILE") {
133 return execWhile(ctx, ast);
134 } else if (ast.type == "IF") {
135 return execIf(ctx, ast);
136 } else if (ast.type == "RETURN") {
137 return execReturn(ctx, ast);
138 } else if (ast.type == "TEMPLATEDEF") {
139 return execTemplateDef(ctx, ast);
140 } else if (ast.type == "FUNCTIONDEF") {
141 return execFunctionDef(ctx, ast);
142 } else if (ast.type == "INCLUDE") {
143 return execInclude(ctx, ast);
144 } else if (ast.type == "ARRAY") {
145 return execArray(ctx, ast);
146 } else {
147 error(ctx, ast, "Invalid AST node type: " + ast.type);
148 }
149}
150
151function error(ctx, ast, errStr) {
152 ctx.error = {
153 pos: {
154 first_line: ast.first_line,
155 first_column: ast.first_column,
156 last_line: ast.last_line,
157 last_column: ast.last_column
158 },
159 errStr: errStr,
160 errFile: ctx.fileName,
161 ast: ast
162 };
163}
164
165function iterateSelectors(ctx, sizes, baseName, fn) {
166 if (sizes.length == 0) {
167 return fn(baseName);
168 }
169 const res = [];
170 for (let i=0; i<sizes[0]; i++) {
171 res.push(iterateSelectors(ctx, sizes.slice(1), baseName+"["+i+"]", fn));
172 if (ctx.error) return null;
173 }
174 return res;
175}
176
177function setScope(ctx, name, selectors, value) {
178 let l = getScopeLevel(ctx, name);
179 if (l==-1) l= ctx.scopes.length-1;
180
181 if (selectors.length == 0) {
182 ctx.scopes[l][name] = value;
183 } else {
184 setScopeArray(ctx.scopes[l][name], selectors);
185 }
186
187 function setScopeArray(a, sels) {
188 if (sels.length == 1) {
189 a[sels[0].value] = value;
190 } else {
191 setScopeArray(a[sels[0]], sels.slice(1));
192 }
193 }
194}
195
196function getScope(ctx, name, selectors) {
197
198 const sels = [];
199 if (selectors) {
200 for (let i=0; i< selectors.length; i++) {
201 const idx = exec(ctx, selectors[i]);
202 if (ctx.error) return;
203
204 if (idx.type != "NUMBER") return error(ctx, selectors[i], "expected a number");
205 sels.push( idx.value.toJSNumber() );
206 }
207 }
208
209
210 function select(v, s) {
211 s = s || [];
212 if (s.length == 0) return v;
213 return select(v[s[0]], s.slice(1));
214 }
215
216 for (let i=ctx.scopes.length-1; i>=0; i--) {
217 if (ctx.scopes[i][name]) return select(ctx.scopes[i][name], sels);
218 }
219 return null;
220}
221
222function getScopeLevel(ctx, name) {
223 for (let i=ctx.scopes.length-1; i>=0; i--) {
224 if (ctx.scopes[i][name]) return i;
225 }
226 return -1;
227}
228
229function execBlock(ctx, ast) {
230 for (let i=0; i<ast.statements.length; i++) {
231 exec(ctx, ast.statements[i]);
232 if (ctx.returnValue) return;
233 if (ctx.error) return;
234 }
235}
236
237function execTemplateDef(ctx, ast) {
238 const scope = ctx.scopes[0]; // Lets put templates always in top scope.
239 // const scope = ctx.scopes[ctx.scopes.length-1];
240 if (getScope(ctx, ast.name)) {
241 return error(ctx, ast, "Name already exists: "+ast.name);
242 }
243 scope[ast.name] = {
244 type: "TEMPLATE",
245 params: ast.params,
246 block: ast.block,
247 fileName: ctx.fileName,
248 filePath: ctx.filePath,
249 scopes: copyScope(ctx.scopes)
250 };
251}
252
253function execFunctionDef(ctx, ast) {
254 const scope = ctx.scopes[0]; // Lets put functions always in top scope.
255 // const scope = ctx.scopes[ctx.scopes.length-1];
256 if (getScope(ctx, ast.name)) {
257 return error(ctx, ast, "Name already exists: "+ast.name);
258 }
259 ctx.functionParams[ast.name] = ast.params;
260 scope[ast.name] = {
261 type: "FUNCTION",
262 params: ast.params,
263 block: ast.block,
264 fileName: ctx.fileName,
265 filePath: ctx.filePath,
266 scopes: copyScope(ctx.scopes)
267 };
268}
269
270
271function execDeclareComponent(ctx, ast) {
272 const scope = ctx.scopes[ctx.scopes.length-1];
273
274 if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
275 if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
276
277 const baseName = ctx.currentComponent ? ctx.currentComponent + "." + ast.name.name : ast.name.name;
278
279 const sizes=[];
280 for (let i=0; i< ast.name.selectors.length; i++) {
281 const size = exec(ctx, ast.name.selectors[i]);
282 if (ctx.error) return;
283
284 if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
285
286 sizes.push( size.value.toJSNumber() );
287 }
288
289
290 scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) {
291
292 ctx.components[fullName] = "UNINSTANTIATED";
293
294 return {
295 type: "COMPONENT",
296 fullName: fullName
297 };
298 });
299
300 return {
301 type: "VARIABLE",
302 name: ast.name.name,
303 selectors: []
304 };
305}
306
307function execInstantiateComponet(ctx, vr, fn) {
308
309 if (vr.type != "VARIABLE") return error(ctx, fn, "Left hand instatiate component must be a variable");
310 if (fn.type != "FUNCTIONCALL") return error(ctx, fn, "Right type of instantiate component must be a function call");
311
312 const componentName = vr.name;
313 const templateName = fn.name;
314
315 const scopeLevel = getScopeLevel(ctx, templateName);
316 if (scopeLevel == -1) return error(ctx,fn, "Invalid Template");
317 const template = getScope(ctx, templateName);
318
319 if (template.type != "TEMPLATE") return error(ctx, fn, "Invalid Template");
320
321
322 const paramValues = [];
323 for (let i=0; i< fn.params.length; i++) {
324 const v = exec(ctx, fn.params[i]);
325 if (ctx.error) return;
326
327 paramValues.push(v);
328 }
329 if (template.params.length != paramValues.length) error(ctx, fn, "Invalid Number of parameters");
330
331 const vv = getScope(ctx, componentName, vr.selectors);
332
333 if (!vv) return error(ctx, vr, "Component not defined"+ componentName);
334
335 instantiateComponent(vv);
336
337 function instantiateComponent(varVal) {
338
339 function extractValue(v) {
340 if (Array.isArray(v)) {
341 return v.map(extractValue);
342 } else {
343 return v.value.toString();
344 }
345 }
346
347 if (Array.isArray(varVal)) {
348 for (let i =0; i<varVal.length; i++) {
349 instantiateComponent(varVal[i]);
350 }
351 return;
352 }
353
354 if (ctx.components[varVal.fullName] != "UNINSTANTIATED") error(ctx, fn, "Component already instantiated");
355
356 const oldComponent = ctx.currentComponent;
357 const oldFileName = ctx.fileName;
358 const oldFilePath = ctx.filePath;
359 ctx.currentComponent = varVal.fullName;
360
361 ctx.components[ctx.currentComponent] = {
362 signals: [],
363 params: {}
364 };
365
366 const oldScopes = ctx.scopes;
367
368 ctx.scopes = oldScopes.slice(0, scopeLevel+1);
369
370 const scope = {};
371 for (let i=0; i< template.params.length; i++) {
372 scope[template.params[i]] = paramValues[i];
373 ctx.components[ctx.currentComponent].params[template.params[i]] = extractValue(paramValues[i]);
374 }
375
376 ctx.components[ctx.currentComponent].template = templateName;
377 ctx.fileName = template.fileName;
378 ctx.filePath = template.filePath;
379 ctx.scopes = copyScope( template.scopes );
380 ctx.scopes.push(scope);
381
382 execBlock(ctx, template.block);
383
384 ctx.fileName = oldFileName;
385 ctx.filePath = oldFilePath;
386 ctx.currentComponent = oldComponent;
387 ctx.scopes = oldScopes;
388 }
389}
390
391function execFunctionCall(ctx, ast) {
392
393 const scopeLevel = getScopeLevel(ctx, ast.name);
394 if (scopeLevel == -1) return error(ctx, ast, "Function not defined: " + ast.name);
395 const fnc = getScope(ctx, ast.name);
396
397 if (fnc.type != "FUNCTION") return error(ctx, ast, "Not a function: " + ast.name);
398
399 const paramValues = [];
400 for (let i=0; i< ast.params.length; i++) {
401 const v = exec(ctx, ast.params[i]);
402 if (ctx.error) return;
403
404 paramValues.push(v);
405 }
406
407 if (ast.params.length != paramValues.length) error(ctx, ast, "Invalid Number of parameters");
408
409 const oldFileName = ctx.fileName;
410 const oldFilePath = ctx.filePath;
411
412 const oldScopes = ctx.scopes;
413
414 ctx.scopes = oldScopes.slice(0, scopeLevel+1);
415
416 const scope = {};
417 for (let i=0; i< fnc.params.length; i++) {
418 scope[fnc.params[i]] = paramValues[i];
419 }
420
421 ctx.fileName = fnc.fileName;
422 ctx.filePath = fnc.filePath;
423 ctx.scopes = copyScope( fnc.scopes );
424 ctx.scopes.push(scope);
425
426 execBlock(ctx, fnc.block);
427
428 const res = ctx.returnValue;
429 ctx.returnValue = null;
430
431 ctx.fileName = oldFileName;
432 ctx.filePath = oldFilePath;
433 ctx.scopes = oldScopes;
434
435 return res;
436}
437
438function execReturn(ctx, ast) {
439 ctx.returnValue = exec(ctx, ast.value);
440 return;
441}
442
443function execDeclareSignal(ctx, ast) {
444 const scope = ctx.scopes[ctx.scopes.length-1];
445
446 if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid component name");
447 if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
448
449 const baseName = ctx.currentComponent ? ctx.currentComponent + "." + ast.name.name : ast.name.name;
450
451 const sizes=[];
452 for (let i=0; i< ast.name.selectors.length; i++) {
453 const size = exec(ctx, ast.name.selectors[i]);
454 if (ctx.error) return;
455
456 if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
457 sizes.push( size.value.toJSNumber() );
458 }
459
460 scope[ast.name.name] = iterateSelectors(ctx, sizes, baseName, function(fullName) {
461 ctx.signals[fullName] = {
462 fullName: fullName,
463 direction: ast.declareType == "SIGNALIN" ? "IN" : (ast.declareType == "SIGNALOUT" ? "OUT" : ""),
464 private: ast.private,
465 component: ctx.currentComponent,
466 equivalence: "",
467 alias: [fullName]
468 };
469 ctx.components[ctx.currentComponent].signals.push(fullName);
470 return {
471 type: "SIGNAL",
472 fullName: fullName,
473 };
474 });
475 return {
476 type: "VARIABLE",
477 name: ast.name.name,
478 selectors: []
479 };
480}
481
482function execDeclareVariable(ctx, ast) {
483 const scope = ctx.scopes[ctx.scopes.length-1];
484
485 if (ast.name.type != "VARIABLE") return error(ctx, ast, "Invalid linear combination name");
486 if (getScope(ctx, ast.name.name)) return error(ctx, ast, "Name already exists: "+ast.name.name);
487
488 const sizes=[];
489 for (let i=0; i< ast.name.selectors.length; i++) {
490 const size = exec(ctx, ast.name.selectors[i]);
491 if (ctx.error) return;
492
493 if (size.type != "NUMBER") return error(ctx, ast.name.selectors[i], "expected a number");
494 sizes.push( size.value.toJSNumber() );
495 }
496
497 scope[ast.name.name] = iterateSelectors(ctx, sizes, "", function() {
498 return {
499 type: "NUMBER",
500 value: bigInt(0)
501 };
502 });
503
504 return {
505 type: "VARIABLE",
506 name: ast.name.name,
507 selectors: []
508 };
509}
510
511function execVariable(ctx, ast) {
512 let v;
513 try {
514 v = getScope(ctx, ast.name, ast.selectors);
515 } catch(err) {
516 console.log(JSON.stringify(ast, null,1));
517 }
518 if (ctx.error) return;
519
520 if (!v) return error(ctx, ast, "Variable not defined");
521
522 // If the signal has an assigned value (constant) just return the constant
523 if ((v.type == "SIGNAL") && (ctx.signals[v.fullName].value)) {
524 return {
525 type: "NUMBER",
526 value: ctx.signals[v.fullName].value
527 };
528 }
529 let res;
530 res=v;
531 return res;
532}
533
534function execPin(ctx, ast) {
535 const component = getScope(ctx, ast.component.name, ast.component.selectors);
536 if (!component) return error(ctx, ast.component, "Component does not exists: "+ast.component.name);
537 if (ctx.error) return;
538 let signalFullName = component.fullName + "." + ast.pin.name;
539 for (let i=0; i< ast.pin.selectors.length; i++) {
540 const sel = exec(ctx, ast.pin.selectors[i]);
541 if (ctx.error) return;
542
543 if (sel.type != "NUMBER") return error(ctx, ast.pin.selectors[i], "expected a number");
544
545 signalFullName += "[" + sel.value.toJSNumber() + "]";
546 }
547 if (!ctx.signals[signalFullName]) error(ctx, ast, "Signal not defined:" + signalFullName);
548 return {
549 type: "SIGNAL",
550 fullName: signalFullName
551 };
552}
553
554function execFor(ctx, ast) {
555
556 ctx.scopes.push({});
557 exec(ctx, ast.init);
558 if (ctx.error) return;
559
560 let v = exec(ctx, ast.condition);
561 if (ctx.error) return;
562
563 if (typeof v.value != "undefined") {
564 while ((v.value.neq(0))&&(!ctx.returnValue)) {
565 exec(ctx, ast.body);
566 if (ctx.error) return;
567
568 exec(ctx, ast.step);
569 if (ctx.error) return;
570
571 v = exec(ctx, ast.condition);
572 if (ctx.error) return;
573 }
574 }
575 ctx.scopes.pop();
576}
577
578function execWhile(ctx, ast) {
579 let v = exec(ctx, ast.condition);
580 if (ctx.error) return;
581
582 if (typeof v.value != "undefined") {
583 while ((v.value.neq(0))&&(!ctx.returnValue)) {
584 exec(ctx, ast.body);
585 if (ctx.error) return;
586
587 v = exec(ctx, ast.condition);
588 if (ctx.error) return;
589 }
590 }
591}
592
593function execIf(ctx, ast) {
594 let v = exec(ctx, ast.condition);
595 if (ctx.error) return;
596
597 if (typeof v.value != "undefined") {
598 if ((v.value.neq(0))&&(!ctx.returnValue)) {
599 exec(ctx, ast.then);
600 if (ctx.error) return;
601 } else {
602 if (ast.else) {
603 exec(ctx, ast.else);
604 if (ctx.error) return;
605 }
606 }
607 }
608}
609
610
611function execVarAssignement(ctx, ast) {
612 let v;
613 if (ast.values[0].type == "DECLARE") {
614 v = exec(ctx, ast.values[0]);
615 if (ctx.error) return;
616 } else {
617 v = ast.values[0];
618 }
619 const num = getScope(ctx, v.name, v.selectors);
620 if (ctx.error) return;
621
622 if ((typeof(num) != "object")||(num == null)) return error(ctx, ast, "Variable not defined");
623
624 if (num.type == "COMPONENT") return execInstantiateComponet(ctx, v, ast.values[1]);
625
626 const res = exec(ctx, ast.values[1]);
627 if (ctx.error) return;
628
629 setScope(ctx, v.name, v.selectors, res);
630
631 return v;
632}
633
634function execLt(ctx, ast) {
635 const a = exec(ctx, ast.values[0]);
636 if (ctx.error) return;
637 if (a.type != "NUMBER") return { type: "NUMBER" };
638 const b = exec(ctx, ast.values[1]);
639 if (ctx.error) return;
640 if (b.type != "NUMBER") return { type: "NUMBER" };
641 if (!a.value || !b.value) return { type: "NUMBER" };
642 return {
643 type: "NUMBER",
644 value: a.value.lt(b.value) ? bigInt(1) : bigInt(0)
645 };
646}
647
648function execGt(ctx, ast) {
649 const a = exec(ctx, ast.values[0]);
650 if (ctx.error) return;
651 if (a.type != "NUMBER") return { type: "NUMBER" };
652 const b = exec(ctx, ast.values[1]);
653 if (ctx.error) return;
654 if (b.type != "NUMBER") return { type: "NUMBER" };
655 if (!a.value || !b.value) return { type: "NUMBER" };
656 return {
657 type: "NUMBER",
658 value: a.value.gt(b.value) ? bigInt(1) : bigInt(0)
659 };
660}
661
662function execLte(ctx, ast) {
663 const a = exec(ctx, ast.values[0]);
664 if (ctx.error) return;
665 if (a.type != "NUMBER") return { type: "NUMBER" };
666 const b = exec(ctx, ast.values[1]);
667 if (ctx.error) return;
668 if (b.type != "NUMBER") return { type: "NUMBER" };
669 if (!a.value || !b.value) return { type: "NUMBER" };
670 return {
671 type: "NUMBER",
672 value: a.value.lesserOrEquals(b.value) ? bigInt(1) : bigInt(0)
673 };
674}
675
676function execGte(ctx, ast) {
677 const a = exec(ctx, ast.values[0]);
678 if (ctx.error) return;
679 if (a.type != "NUMBER") return { type: "NUMBER" };
680 const b = exec(ctx, ast.values[1]);
681 if (ctx.error) return;
682 if (b.type != "NUMBER") return { type: "NUMBER" };
683 if (!a.value || !b.value) return { type: "NUMBER" };
684 return {
685 type: "NUMBER",
686 value: a.value.greaterOrEquals(b.value) ? bigInt(1) : bigInt(0)
687 };
688}
689
690
691function execEq(ctx, ast) {
692 const a = exec(ctx, ast.values[0]);
693 if (ctx.error) return;
694 if (a.type != "NUMBER") return { type: "NUMBER" };
695 const b = exec(ctx, ast.values[1]);
696 if (ctx.error) return;
697 if (b.type != "NUMBER") return { type: "NUMBER" };
698 if (!a.value || !b.value) return { type: "NUMBER" };
699 return {
700 type: "NUMBER",
701 value: a.value.eq(b.value) ? bigInt(1) : bigInt(0)
702 };
703}
704
705function execNeq(ctx, ast) {
706 const a = exec(ctx, ast.values[0]);
707 if (ctx.error) return;
708 if (a.type != "NUMBER") return { type: "NUMBER" };
709 const b = exec(ctx, ast.values[1]);
710 if (ctx.error) return;
711 if (b.type != "NUMBER") return { type: "NUMBER" };
712 if (!a.value || !b.value) return { type: "NUMBER" };
713 return {
714 type: "NUMBER",
715 value: a.value.eq(b.value) ? bigInt(0) : bigInt(1)
716 };
717}
718
719
720function execBAnd(ctx, ast) {
721 const a = exec(ctx, ast.values[0]);
722 if (ctx.error) return;
723 if (a.type != "NUMBER") return { type: "NUMBER" };
724 const b = exec(ctx, ast.values[1]);
725 if (ctx.error) return;
726 if (b.type != "NUMBER") return { type: "NUMBER" };
727 if (!a.value || !b.value) return { type: "NUMBER" };
728 return {
729 type: "NUMBER",
730 value: a.value.and(b.value).and(__MASK__)
731 };
732}
733
734function execAnd(ctx, ast) {
735 const a = exec(ctx, ast.values[0]);
736 if (ctx.error) return;
737 if (a.type != "NUMBER") return { type: "NUMBER" };
738 const b = exec(ctx, ast.values[1]);
739 if (ctx.error) return;
740 if (b.type != "NUMBER") return { type: "NUMBER" };
741 if (!a.value || !b.value) return { type: "NUMBER" };
742 return {
743 type: "NUMBER",
744 value: (a.value.neq(0) && a.value.neq(0)) ? bigInt(1) : bigInt(0)
745 };
746}
747
748function execOr(ctx, ast) {
749 const a = exec(ctx, ast.values[0]);
750 if (ctx.error) return;
751 if (a.type != "NUMBER") return { type: "NUMBER" };
752 const b = exec(ctx, ast.values[1]);
753 if (ctx.error) return;
754 if (b.type != "NUMBER") return { type: "NUMBER" };
755 if (!a.value || !b.value) return { type: "NUMBER" };
756 return {
757 type: "NUMBER",
758 value: (a.value.neq(0) || a.value.neq(0)) ? bigInt(1) : bigInt(0)
759 };
760}
761
762function execShl(ctx, ast) {
763 const a = exec(ctx, ast.values[0]);
764 if (ctx.error) return;
765 if (a.type != "NUMBER") return { type: "NUMBER" };
766 const b = exec(ctx, ast.values[1]);
767 if (ctx.error) return;
768 if (b.type != "NUMBER") return { type: "NUMBER" };
769 if (!a.value || !b.value) return { type: "NUMBER" };
770 const v = b.value.greater(256) ? 256 : b.value.value;
771 return {
772 type: "NUMBER",
773 value: a.value.shiftLeft(v).and(__MASK__)
774 };
775}
776
777function execShr(ctx, ast) {
778 const a = exec(ctx, ast.values[0]);
779 if (ctx.error) return;
780 if (a.type != "NUMBER") return { type: "NUMBER" };
781 const b = exec(ctx, ast.values[1]);
782 if (ctx.error) return;
783 if (b.type != "NUMBER") return { type: "NUMBER" };
784 if (!a.value || !b.value) return { type: "NUMBER" };
785 const v = b.value.greater(256) ? 256 : b.value.value;
786 return {
787 type: "NUMBER",
788 value: a.value.shiftRight(v).and(__MASK__)
789 };
790}
791
792function execMod(ctx, ast) {
793 const a = exec(ctx, ast.values[0]);
794 if (ctx.error) return;
795 if (a.type != "NUMBER") return { type: "NUMBER" };
796 const b = exec(ctx, ast.values[1]);
797 if (ctx.error) return;
798 if (b.type != "NUMBER") return { type: "NUMBER" };
799 if (!a.value || !b.value) return { type: "NUMBER" };
800 return {
801 type: "NUMBER",
802 value: a.value.mod(b.value)
803 };
804}
805
806
807function execExp(ctx, ast) {
808 const a = exec(ctx, ast.values[0]);
809 if (ctx.error) return;
810 if (a.type != "NUMBER") return { type: "NUMBER" };
811 const b = exec(ctx, ast.values[1]);
812 if (ctx.error) return;
813 if (b.type != "NUMBER") return { type: "NUMBER" };
814 if (!a.value || !b.value) return { type: "NUMBER" };
815 return {
816 type: "NUMBER",
817 value: a.value.modPow(b.value, __P__)
818 };
819}
820
821function execDiv(ctx, ast) {
822 const a = exec(ctx, ast.values[0]);
823 if (ctx.error) return;
824 if (a.type != "NUMBER") return { type: "NUMBER" };
825 const b = exec(ctx, ast.values[1]);
826 if (ctx.error) return;
827 if (b.type != "NUMBER") return { type: "NUMBER" };
828 if (!a.value || !b.value) return { type: "NUMBER" };
829 if (b.value.isZero()) return error(ctx, ast, "Division by zero");
830 return {
831 type: "NUMBER",
832 value: a.value.times(b.value.modInv(__P__)).mod(__P__)
833 };
834}
835
836function execIDiv(ctx, ast) {
837 const a = exec(ctx, ast.values[0]);
838 if (ctx.error) return;
839 if (a.type != "NUMBER") return { type: "NUMBER" };
840 const b = exec(ctx, ast.values[1]);
841 if (ctx.error) return;
842 if (b.type != "NUMBER") return { type: "NUMBER" };
843 if (!a.value || !b.value) return { type: "NUMBER" };
844 if (b.value.isZero()) return error(ctx, ast, "Division by zero");
845 return {
846 type: "NUMBER",
847 value: a.value.divide(b.value)
848 };
849}
850
851function execAdd(ctx, ast) {
852 const a = exec(ctx, ast.values[0]);
853 if (ctx.error) return;
854 const b = exec(ctx, ast.values[1]);
855 if (ctx.error) return;
856
857 const res = lc.add(a,b);
858 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
859
860 return res;
861}
862
863function execSub(ctx, ast) {
864 const a = exec(ctx, ast.values[0]);
865 if (ctx.error) return;
866 const b = exec(ctx, ast.values[1]);
867 if (ctx.error) return;
868
869 const res = lc.sub(a,b);
870 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
871
872 return res;
873}
874
875function execUMinus(ctx, ast) {
876 const a = exec(ctx, ast.values[0]);
877 if (ctx.error) return;
878
879 const res = lc.negate(a);
880 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
881
882 return res;
883}
884
885function execMul(ctx, ast) {
886 const a = exec(ctx, ast.values[0]);
887 if (ctx.error) return;
888 const b = exec(ctx, ast.values[1]);
889 if (ctx.error) return;
890
891 const res = lc.mul(a,b);
892 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
893
894 return res;
895}
896
897
898function execVarAddAssignement(ctx, ast) {
899 const res = execAdd(ctx,{ values: [ast.values[0], ast.values[1]] } );
900 if (ctx.error) return;
901 return execVarAssignement(ctx, { values: [ast.values[0], res] });
902}
903
904function execVarMulAssignement(ctx, ast) {
905 const res = execMul(ctx,{ values: [ast.values[0], ast.values[1]] } );
906 if (ctx.error) return;
907 return execVarAssignement(ctx, { values: [ast.values[0], res] });
908}
909
910function execPlusPlusRight(ctx, ast) {
911 const resBefore = exec(ctx, ast.values[0]);
912 if (ctx.error) return;
913 const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
914 if (ctx.error) return;
915 execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
916 return resBefore;
917}
918
919function execPlusPlusLeft(ctx, ast) {
920 if (ctx.error) return;
921 const resAfter = execAdd(ctx,{ values: [ast.values[0], {type: "NUMBER", value: bigInt(1)}] } );
922 if (ctx.error) return;
923 execVarAssignement(ctx, { values: [ast.values[0], resAfter] });
924 return resAfter;
925}
926
927function execTerCon(ctx, ast) {
928 const cond = exec(ctx, ast.values[0]);
929 if (ctx.error) return;
930
931 if (!cond.value) return { type: "NUMBER" };
932
933 if (cond.value.neq(0)) {
934 return exec(ctx, ast.values[1]);
935 } else {
936 return exec(ctx, ast.values[2]);
937 }
938}
939
940function execSignalAssign(ctx, ast) {
941 let vDest;
942 if (ast.values[0].type == "DECLARE") {
943 vDest = exec(ctx, ast.values[0]);
944 if (ctx.error) return;
945 } else {
946 vDest = ast.values[0];
947 }
948
949 let dst;
950 if (vDest.type == "VARIABLE") {
951 dst = getScope(ctx, vDest.name, vDest.selectors);
952 if (ctx.error) return;
953 } else if (vDest.type == "PIN") {
954 dst = execPin(ctx, vDest);
955 if (ctx.error) return;
956 } else {
957 error(ctx, ast, "Bad assignement");
958 }
959
960 if (!dst) return error(ctx, ast, "Signal not defined");
961 if (dst.type != "SIGNAL") return error(ctx, ast, "Signal assigned to a non signal");
962
963 let sDest=ctx.signals[dst.fullName];
964 if (!sDest) return error(ctx, ast, "Invalid signal: "+dst.fullName);
965 while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
966
967 if (sDest.value) return error(ctx, ast, "Signals cannot be assigned twice");
968
969 let src = exec(ctx, ast.values[1]);
970 if (ctx.error) return;
971
972
973 /*
974 let vSrc;
975 if (ast.values[1].type == "DECLARE") {
976 vSrc = exec(ctx, ast.values[1]);
977 if (ctx.error) return;
978 } else {
979 vSrc = ast.values[1];
980 }
981
982 if (vSrc.type == "VARIABLE") {
983 src = getScope(ctx, vSrc.name, vSrc.selectors);
984 if (!src) error(ctx, ast, "Variable not defined: " + vSrc.name);
985 if (ctx.error) return;
986 } else if (vSrc.type == "PIN") {
987 src = execPin(ctx, vSrc);
988 }
989 */
990
991 let assignValue = true;
992 if (src.type == "SIGNAL") {
993 sDest.equivalence = src.fullName;
994 sDest.alias = sDest.alias.concat(src.alias);
995 while (sDest.equivalence) sDest=ctx.signals[sDest.equivalence];
996 assignValue = false;
997 }
998
999 if (assignValue) {
1000 // const resLC = exec(ctx, vSrc);
1001 if (ctx.error) return;
1002
1003 // const v = lc.evaluate(ctx, resLC);
1004 const v = lc.evaluate(ctx, src);
1005
1006 if (v.value) {
1007 sDest.value = v.value;
1008 }
1009 }
1010
1011 return vDest;
1012}
1013
1014function execConstrain(ctx, ast) {
1015 const a = exec(ctx, ast.values[0]);
1016 if (ctx.error) return;
1017 const b = exec(ctx, ast.values[1]);
1018 if (ctx.error) return;
1019
1020 const res = lc.sub(a,b);
1021 if (res.type == "ERROR") return error(ctx, ast, res.errStr);
1022
1023 if (!lc.isZero(res)) {
1024 ctx.constraints.push(lc.toQEQ(res));
1025 }
1026
1027 return res;
1028}
1029
1030function execSignalAssignConstrain(ctx, ast) {
1031 const v = execSignalAssign(ctx,ast);
1032 if (ctx.error) return;
1033 execConstrain(ctx, ast);
1034 if (ctx.error) return;
1035 return v;
1036}
1037
1038function execInclude(ctx, ast) {
1039 const incFileName = path.resolve(ctx.filePath, ast.file);
1040 const incFilePath = path.dirname(incFileName);
1041
1042 ctx.includedFiles = ctx.includedFiles || [];
1043 if (ctx.includedFiles[incFileName]) return;
1044
1045 ctx.includedFiles[incFileName] = true;
1046
1047 const src = fs.readFileSync(incFileName, "utf8");
1048
1049 if (!src) return error(ctx, ast, "Include file not found: "+incFileName);
1050
1051 const incAst = parser.parse(src);
1052
1053 const oldFilePath = ctx.filePath;
1054 const oldFileName = ctx.fileName;
1055 ctx.filePath = incFilePath;
1056 ctx.fileName = incFileName;
1057
1058 exec(ctx, incAst);
1059
1060 ast.block = incAst;
1061
1062 ctx.filePath = oldFilePath;
1063 ctx.fileName = oldFileName;
1064}
1065
1066function execArray(ctx, ast) {
1067 const res = [];
1068
1069 for (let i=0; i<ast.values.length; i++) {
1070 res.push(exec(ctx, ast.values[i]));
1071 }
1072
1073 return res;
1074}
1075
1076function copyScope(scope) {
1077 var scopesClone = [];
1078 for (let i=0; i<scope.length; i++) {
1079 scopesClone.push(scope[i]);
1080 }
1081 return scopesClone;
1082}
1083