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