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