You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1082 lines
33 KiB

4 years ago
  1. /*
  2. Copyright 2018 0KIMS association.
  3. This file is part of circom (Zero Knowledge Circuit Compiler).
  4. circom is a free software: you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. circom is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  11. License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with circom. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. The exec functions, return an object of the form:
  17. {
  18. t: "C" or "V" or "S"
  19. s: Accumulated Sizes
  20. v: [] only when "V" Array of values where each value is:
  21. {
  22. t: "N", "S", "LC", "QEX", "NQ"
  23. v: When "N" its the bigInt of the number
  24. coefs: { sIdx: vCoef } when "LC" the values of the coefs
  25. a,b,c: a LC object of a quadratic expression.
  26. }
  27. refId: In case of a variable, the reference of a variable.
  28. sIdx: When signal, the sIdx
  29. cIdx: When component, the cIdx
  30. }
  31. */
  32. const path = require("path");
  33. const fs = require("fs");
  34. const assert = require("assert");
  35. const iterateAST = require("./iterateast");
  36. const utils = require("./utils");
  37. const LCAlgebra = require("./lcalgebra");
  38. const parser = require("../parser/jaz.js").parser;
  39. const Scalar = require("ffjavascript").Scalar;
  40. const {stringifyBigInts} = require("ffjavascript").utils;
  41. /* TODO: Add lines information
  42. function setLines(dst, first, last) {
  43. last = last || first;
  44. dst.first_line = first.first_line;
  45. dst.first_column = first.first_column;
  46. dst.last_line = last.last_line;
  47. dst.last_column = last.last_column;
  48. }
  49. */
  50. module.exports = constructionPhase;
  51. const NQVAL = {t: "V", s:[1,0], v: [{t:"NQ"}]};
  52. function constructionPhase(ctx, srcFile) {
  53. const fullFileName = srcFile;
  54. const fullFilePath = path.dirname(fullFileName);
  55. const src = fs.readFileSync(fullFileName, "utf8");
  56. ctx.ast = parser.parse(src);
  57. assert(ctx.ast.type == "BLOCK");
  58. ctx.lc = new LCAlgebra(ctx.F);
  59. ctx.filePath= fullFilePath;
  60. ctx.fileName= fullFileName;
  61. ctx.includedFiles = {};
  62. ctx.includedFiles[fullFileName] = src.split("\n");
  63. ctx.refs = [];
  64. createRefs(ctx, ctx.ast);
  65. exec(ctx, ctx.ast);
  66. }
  67. function exec(ctx, ast) {
  68. if (!ast) {
  69. return ctx.throwError(ast, "Null AST");
  70. }
  71. if (ast.type == "NUMBER") {
  72. return execNumber(ctx,ast);
  73. } else if (ast.type == "VARIABLE") {
  74. return execVariable(ctx, ast);
  75. } else if (ast.type == "PIN") {
  76. return execPin(ctx, ast);
  77. } else if (ast.type == "OP") {
  78. if (ast.op == "=") {
  79. return execAssignement(ctx, ast);
  80. } else if (ast.op == "<--") {
  81. return execAssignement(ctx, ast);
  82. } else if (ast.op == "<==") {
  83. return execSignalAssignConstrain(ctx, ast);
  84. } else if (ast.op == "===") {
  85. return execConstrain(ctx, ast);
  86. } else if (ast.op == "+=") {
  87. return execOpOp(ctx, ast, "add", "LEFT");
  88. } else if (ast.op == "*=") {
  89. return execOpOp(ctx, ast, "mul", "LEFT");
  90. } else if (ast.op == "+") {
  91. return execOp(ctx, ast, "add", 2);
  92. } else if (ast.op == "-") {
  93. return execOp(ctx, ast, "sub", 2);
  94. } else if (ast.op == "UMINUS") {
  95. return execOp(ctx, ast, "neg", 1);
  96. } else if (ast.op == "*") {
  97. return execOp(ctx, ast, "mul", 2);
  98. } else if (ast.op == "%") {
  99. return execOp(ctx, ast, "mod", 2);
  100. } else if (ast.op == "PLUSPLUSRIGHT") {
  101. return execOpOp(ctx, ast, "add", "RIGHT");
  102. } else if (ast.op == "PLUSPLUSLEFT") {
  103. return execOpOp(ctx, ast, "add", "LEFT");
  104. } else if (ast.op == "MINUSMINUSRIGHT") {
  105. return execOpOp(ctx, ast, "sub", "RIGHT");
  106. } else if (ast.op == "MINUSMINUSLEFT") {
  107. return execOpOp(ctx, ast, "sub", "LEFT");
  108. } else if (ast.op == "/") {
  109. return execOp(ctx, ast, "div", 2);
  110. } else if (ast.op == "\\") {
  111. return execOp(ctx, ast, "idiv", 2);
  112. } else if (ast.op == "**") {
  113. return execOp(ctx, ast, "pow", 2);
  114. } else if (ast.op == "&") {
  115. return execOp(ctx, ast, "band", 2);
  116. } else if (ast.op == "|") {
  117. return execOp(ctx, ast, "bor", 2);
  118. } else if (ast.op == "^") {
  119. return execOp(ctx, ast, "bxor", 2);
  120. } else if (ast.op == "~") {
  121. return execOp(ctx, ast, "bnot", 1);
  122. } else if (ast.op == "&&") {
  123. return execOp(ctx, ast, "land", 2);
  124. } else if (ast.op == "||") {
  125. return execOp(ctx, ast, "lor", 2);
  126. } else if (ast.op == "!") {
  127. return execOp(ctx, ast, "lnot", 1);
  128. } else if (ast.op == "<<") {
  129. return execOp(ctx, ast, "shl", 2);
  130. } else if (ast.op == ">>") {
  131. return execOp(ctx, ast, "shr", 2);
  132. } else if (ast.op == "<") {
  133. return execOp(ctx, ast, "lt", 2);
  134. } else if (ast.op == ">") {
  135. return execOp(ctx, ast, "gt", 2);
  136. } else if (ast.op == "<=") {
  137. return execOp(ctx, ast, "leq", 2);
  138. } else if (ast.op == ">=") {
  139. return execOp(ctx, ast, "geq", 2);
  140. } else if (ast.op == "==") {
  141. return execOp(ctx, ast, "eq", 2);
  142. } else if (ast.op == "!=") {
  143. return execOp(ctx, ast, "neq", 2);
  144. } else if (ast.op == "?") {
  145. return execTerCon(ctx, ast);
  146. } else {
  147. ctx.throwError(ast, "Invalid operation: " + ast.op);
  148. }
  149. } else if (ast.type == "DECLARE") {
  150. if (ast.declareType == "COMPONENT") {
  151. return execDeclareComponent(ctx, ast);
  152. } else if ((ast.declareType == "SIGNALIN")||
  153. (ast.declareType == "SIGNALOUT")||
  154. (ast.declareType == "SIGNAL")) {
  155. return execDeclareSignal(ctx, ast);
  156. } else if (ast.declareType == "VARIABLE") {
  157. return execDeclareVariable(ctx, ast);
  158. } else {
  159. ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
  160. }
  161. } else if (ast.type == "FUNCTIONCALL") {
  162. return execFunctionCall(ctx, ast);
  163. } else if (ast.type == "BLOCK") {
  164. return execBlock(ctx, ast);
  165. } else if (ast.type == "COMPUTE") {
  166. return execCompute(ctx, ast);
  167. } else if (ast.type == "FOR") {
  168. return execLoop(ctx, ast);
  169. } else if (ast.type == "WHILE") {
  170. return execLoop(ctx, ast);
  171. } else if (ast.type == "IF") {
  172. return execIf(ctx, ast);
  173. } else if (ast.type == "RETURN") {
  174. return execReturn(ctx, ast);
  175. } else if (ast.type == "TEMPLATEDEF") {
  176. return execTemplateDef(ctx, ast);
  177. } else if (ast.type == "FUNCTIONDEF") {
  178. return execFunctionDef(ctx, ast);
  179. } else if (ast.type == "INCLUDE") {
  180. return execInclude(ctx, ast);
  181. } else if (ast.type == "ARRAY") {
  182. return execArray(ctx, ast);
  183. } else {
  184. ctx.throwError(ast, "Invalid AST node type: " + ast.type);
  185. }
  186. }
  187. function execNumber(ctx, ast) {
  188. return {
  189. t: "V",
  190. s:[1,0],
  191. v: [{
  192. t: "N",
  193. v: ctx.F.e(ast.value)
  194. }]
  195. };
  196. }
  197. function execTemplateDef(ctx, ast) {
  198. ctx.templates[ast.name] = {
  199. block: ast.block,
  200. params: ast.params,
  201. fileName: ctx.fileName,
  202. filePath: ctx.filePath,
  203. };
  204. }
  205. function execFunctionDef(ctx, ast) {
  206. ctx.functions[ast.name] = {
  207. block: ast.block,
  208. params: ast.params,
  209. fileName: ctx.fileName,
  210. filePath: ctx.filePath
  211. };
  212. }
  213. function execDeclareComponent(ctx, ast) {
  214. if (ast.name.type != "VARIABLE") return ctx.throwError( ast, "Invalid component name");
  215. const sizes=[];
  216. for (let i=0; i< ast.name.selectors.length; i++) {
  217. const sizeRef = exec(ctx, ast.name.selectors[i]);
  218. if (ctx.error) return;
  219. const size = val(ctx, sizeRef);
  220. if (size.t != "N") return ctx.throwError( ast.name.selectors[i], "expected a number");
  221. sizes.push( Scalar.toNumber(size.v) );
  222. }
  223. let cIdx = ctx.addComponent(ast.name.name, sizes);
  224. if (!Array.isArray(cIdx)) cIdx = [cIdx, cIdx+1];
  225. ctx.refs[ast.refId].s = utils.accSizes(sizes);
  226. ctx.refs[ast.refId].cIdx = cIdx[0];
  227. return ctx.refs[ast.refId];
  228. }
  229. function execDeclareSignal(ctx, ast) {
  230. if (ast.name.type != "VARIABLE") return ctx.throwError(ast, "Invalid component name");
  231. const sizes=[];
  232. for (let i=0; i< ast.name.selectors.length; i++) {
  233. const size = exec(ctx, ast.name.selectors[i]);
  234. if (ctx.error) return;
  235. if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
  236. if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
  237. sizes.push( Scalar.toNumber(size.v[0].v) );
  238. }
  239. let sIdx = ctx.addSignal(ast.name.name, sizes);
  240. if (!Array.isArray(sIdx)) sIdx = [sIdx, sIdx+1];
  241. for (let i=sIdx[0]; i<sIdx[1]; i++) {
  242. ctx.signals[i] = {
  243. o: 0,
  244. e: -1
  245. };
  246. if (ast.declareType == "SIGNALIN") {
  247. ctx.signals[i].o |= ctx.IN;
  248. ctx.components[ctx.currentComponent].nInSignals+=1;
  249. }
  250. if (ast.declareType == "SIGNALOUT") {
  251. ctx.signals[i].o |= ctx.OUT;
  252. }
  253. if (ast.private ) {
  254. ctx.signals[i].o |= ctx.PRV;
  255. }
  256. if (ctx.main) {
  257. ctx.signals[i].o |= ctx.MAIN;
  258. }
  259. // ctx.components[ctx.currentComponent].signals.push(i);
  260. }
  261. const v = ctx.refs[ast.refId];
  262. v.s = utils.accSizes(sizes);
  263. v.sIdx = sIdx[0];
  264. return v;
  265. }
  266. function execDeclareVariable(ctx, ast) {
  267. if (ast.name.type != "VARIABLE") return ctx.throwError(ast, "Invalid linear combination name");
  268. const sizes=[];
  269. for (let i=0; i< ast.name.selectors.length; i++) {
  270. const size = exec(ctx, ast.name.selectors[i]);
  271. if (ctx.error) return;
  272. if (size.s[0] != 1) return ctx.throwError(ast, "Size cannot be an array");
  273. if (size.v[0].t != "N") return ctx.throwError(ast, "Size must be declared in construction time");
  274. sizes.push( Scalar.toNumber(size.v[0].v) );
  275. }
  276. const v = ctx.refs[ast.refId];
  277. v.s = utils.accSizes(sizes);
  278. v.v = new Array(v.s[0]);
  279. return v;
  280. }
  281. function execAssignement(ctx, ast) {
  282. let left;
  283. const leftSels=[];
  284. if (ast.values[0].type == "DECLARE") {
  285. left = exec(ctx, ast.values[0]);
  286. if (ctx.error) return;
  287. } else if (ast.values[0].type == "PIN") {
  288. left = execPin(ctx, ast.values[0]);
  289. if (ctx.error) return;
  290. } else {
  291. if (!utils.isDefined(ast.values[0].refId)) return ctx.throwError(ast, "Assigning to a non variable");
  292. left = ctx.refs[ast.values[0].refId];
  293. if (ast.values[0].selectors) {
  294. for (let i=0; i< ast.values[0].selectors.length; i++) {
  295. const sel = exec(ctx, ast.values[0].selectors[i]);
  296. if (ctx.error) return;
  297. if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
  298. if (sel.v[0].t != "N") return {t: "NQ"};
  299. leftSels.push( Scalar.toNumber(sel.v[0].v) );
  300. }
  301. }
  302. }
  303. if ((!left)||(!left.s)) return ctx.throwError(ast, "variable. not defined yet");
  304. if (left.t == "C") return execInstantiateComponet(ctx, left, ast.values[1], leftSels);
  305. if ((left.t == "S")&&( ["<--", "<==", "-->", "==>"].indexOf(ast.op) < 0)) return ctx.throwError(ast, "Cannot assign to a signal with `=` use <-- or <== ops");
  306. if ((left.t == "V")&&( ["<--", "<==", "-->", "==>"].indexOf(ast.op) >= 0)) return ctx.throwError(ast, `Cannot assign to a var with ${ast.op}. use = op`);
  307. const right = exec(ctx, ast.values[1]);
  308. if (ctx.error) return;
  309. if (!utils.sameSizes(left.s.slice(leftSels.length),right.s)) return ctx.throwError(ast, "Sizes in assignment must be the same");
  310. let o = 0;
  311. for (let i=0; i<leftSels.length; i++) o += leftSels[i]*left.s[i+1];
  312. if (left.t == "V") {
  313. if (right.t=="V") {
  314. for (let i=0; i<right.s[0]; i++) {
  315. left.v[o+i]=right.v[i];
  316. }
  317. } else if (right.t == "S") {
  318. for (let i=0; i<right.s[0]; i++) {
  319. left.v[o+i]={t: "LC", coefs: {}};
  320. left.v[o+i].coefs[right.sIdx+i] = ctx.F.one;
  321. }
  322. }
  323. } else if ( left.t == "S") {
  324. if (right.t=="V") {
  325. for (let i=0; i<right.s[0]; i++) {
  326. const ev = ctx.lc.evaluate(ctx, right.v[i]);
  327. setSignalValue(left.sIdx + o +i, ev);
  328. }
  329. } else if (right.t == "S") {
  330. for (let i=0; i<right.s[0]; i++) {
  331. joinSignals(left.sIdx + o + i, right.sIdx + i);
  332. }
  333. }
  334. }
  335. return right;
  336. function setSignalValue(dSIdx, v) {
  337. let sDest = ctx.signals[dSIdx];
  338. while (sDest.e>=0) sDest=ctx.signals[sDest.e];
  339. if (utils.isDefined(sDest.v)) return ctx.throwError(ast, "Signals cannot be assigned twice");
  340. if (v !== null) {
  341. sDest.v = v;
  342. }
  343. }
  344. function joinSignals(dIdx, sIdx) {
  345. let sDest=ctx.signals[dIdx];
  346. let isOut = (sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT);
  347. while (sDest.e>=0) {
  348. sDest=ctx.signals[sDest.e];
  349. isOut = isOut || ((sDest.o & ctx.MAIN)&&(sDest.o & ctx.OUT));
  350. }
  351. if (utils.isDefined(sDest.v)) return ctx.throwError(ast, "Signals cannot be assigned twice");
  352. let sSrc = ctx.signals[sIdx];
  353. let isIn = (sSrc.o & ctx.MAIN)&&(sSrc.o & ctx.IN);
  354. while (sSrc.e>=0) {
  355. sSrc=ctx.signals[sSrc.e];
  356. isIn = isIn || ((sSrc.o & ctx.MAIN)&&(sSrc.o & ctx.IN));
  357. }
  358. // Skip if an out is assigned directly to an input.
  359. if ((!isIn)||(!isOut)) {
  360. sDest.e = sIdx;
  361. } else {
  362. if (utils.isDefined(sSrc.v)) sDest.v = sSrc.v;
  363. }
  364. }
  365. }
  366. function execInstantiateComponet(ctx, vr, fn, sels) {
  367. if (fn.type != "FUNCTIONCALL") return ctx.throwError(fn, "Right type of instantiate component must be a function call");
  368. const templateName = fn.name;
  369. const template = ctx.templates[templateName];
  370. if (!template) return ctx.throwError(fn, "Invalid Template");
  371. const paramValues = [];
  372. for (let i=0; i< fn.params.length; i++) {
  373. const v = exec(ctx, fn.params[i]);
  374. if (ctx.error) return;
  375. for (let j=0; j<v.s[0]; j++) {
  376. if (v.v[j].t != "N") ctx.throwError(fn, "Parameters of a template must be constant");
  377. }
  378. paramValues.push(v);
  379. }
  380. if (template.params.length != paramValues.length) ctx.throwError(fn, "Invalid Number of parameters");
  381. let o=0;
  382. for (let i=0; i<sels.length; i++) o += sels[i] * vr.s[i+1];
  383. for (let i=o; i<o+vr.s[sels.length]; i++) {
  384. instantiateComponent(vr.cIdx+i);
  385. }
  386. function instantiateComponent(cIdx) {
  387. function extractValue(sizes, arr) {
  388. if (sizes[0] == 1) return arr[0].v.toString();
  389. const res = [];
  390. for (let i=0; i<sizes[0]; i += sizes[1]) {
  391. res.push(extractValue(sizes.slice(1), arr.slice(i, i+sizes[1])));
  392. }
  393. return res;
  394. }
  395. if (ctx.components[cIdx]) return ctx.throwError(fn, "Component already instantiated");
  396. const oldComponent = ctx.currentComponent;
  397. const oldFileName = ctx.fileName;
  398. const oldFilePath = ctx.filePath;
  399. const oldMain = ctx.main;
  400. const oldRefs = ctx.refs;
  401. if (ctx.currentComponent==-1) {
  402. ctx.main=true;
  403. } else {
  404. ctx.main=false;
  405. }
  406. ctx.currentComponent = cIdx;
  407. ctx.components[cIdx] = {
  408. params: {},
  409. names: ctx.newTableName(),
  410. nInSignals: 0,
  411. template: templateName
  412. };
  413. if (template.params.length != paramValues.length) return ctx.throwError(fn, "Invalid number of parameters: " + templateName);
  414. ctx.refs = [];
  415. const scope = {};
  416. for (let i=0; i< template.params.length; i++) {
  417. ctx.refs.push({
  418. t: "V",
  419. s: paramValues[i].s,
  420. v: paramValues[i].v,
  421. refId: i
  422. });
  423. scope[template.params[i]] = i;
  424. ctx.components[cIdx].params[template.params[i]] = extractValue(paramValues[i].s, paramValues[i].v);
  425. }
  426. createRefs(ctx, template.block, scope);
  427. ctx.fileName = template.fileName;
  428. ctx.filePath = template.filePath;
  429. execBlock(ctx, template.block);
  430. ctx.refs = oldRefs;
  431. ctx.fileName = oldFileName;
  432. ctx.filePath = oldFilePath;
  433. ctx.currentComponent = oldComponent;
  434. ctx.main = oldMain;
  435. }
  436. }
  437. function execBlock(ctx, ast) {
  438. for (let i=0; i<ast.statements.length; i++) {
  439. exec(ctx, ast.statements[i]);
  440. if (ctx.returnValue) return;
  441. if (ctx.error) return;
  442. }
  443. }
  444. function clone(a) {
  445. const res = {
  446. t: a.t,
  447. s: a.s
  448. };
  449. if (a.t == "V") {
  450. res.v = new Array(a.v.length);
  451. for (let i=0; i<a.v.length; i++) res.v[i] = a.v[i];
  452. } else if (a.t == "S") {
  453. res.sIdx = a.sIdx;
  454. } else if (a.t == "C") {
  455. res.cIdx = a.cIdx;
  456. }
  457. return res;
  458. }
  459. function execFunctionCall(ctx, ast) {
  460. if (ast.name == "log") {
  461. const v = exec(ctx, ast.params[0]);
  462. const ev = val(ctx, v, ast);
  463. if (ev.v) {
  464. console.log(ev.v.toString());
  465. } else {
  466. console.log(JSON.stringify(stringifyBigInts(ev)));
  467. }
  468. return;
  469. }
  470. if (ast.name == "assert") {
  471. const v = exec(ctx, ast.params[0]);
  472. const ev = val(ctx, v, ast);
  473. if (ctx.F.isZero(ev)) return ctx.throwError(ast, "Assertion failed");
  474. }
  475. const fnc = ctx.functions[ast.name];
  476. if (!fnc) return ctx.throwError("Function not defined");
  477. const paramValues = [];
  478. for (let i=0; i< ast.params.length; i++) {
  479. const v = exec(ctx, ast.params[i]);
  480. if (ctx.error) return;
  481. paramValues.push(v);
  482. }
  483. if (ast.params.length != paramValues.length) ctx.throwError(ast, "Invalid Number of parameters");
  484. const oldFileName = ctx.fileName;
  485. const oldFilePath = ctx.filePath;
  486. const oldRefs = ctx.refs;
  487. ctx.fileName = fnc.fileName;
  488. ctx.filePath = fnc.filePath;
  489. ctx.refs = [];
  490. const scope = {};
  491. for (let i=0; i< fnc.params.length; i++) {
  492. const entry = clone(paramValues[i]);
  493. entry.refId = i;
  494. scope[fnc.params[i]] = i;
  495. ctx.refs.push(entry);
  496. }
  497. createRefs(ctx, fnc.block, scope);
  498. execBlock(ctx, fnc.block);
  499. const res = ctx.returnValue;
  500. ctx.returnValue = null;
  501. ctx.fileName = oldFileName;
  502. ctx.filePath = oldFilePath;
  503. ctx.refs = oldRefs;
  504. return res;
  505. }
  506. function execReturn(ctx, ast) {
  507. ctx.returnValue = exec(ctx, ast.value);
  508. return;
  509. }
  510. function execVariable(ctx, ast) {
  511. const v = ctx.refs[ast.refId];
  512. if (!v) {
  513. return ctx.throwError(ast, "Variable not defined: "+ast.name);
  514. }
  515. const sels = [];
  516. for (let i=0; i< ast.selectors.length; i++) {
  517. const sel = exec(ctx, ast.selectors[i]);
  518. if (ctx.error) return;
  519. if (sel.s[0] != 1) return ctx.throwError(ast, "Variable selector cannot be an array");
  520. if (sel.v[0].t != "N") return NQVAL;
  521. sels.push(Scalar.toNumber(sel.v[0].v));
  522. }
  523. let o = 0;
  524. let s = v.s[0];
  525. if (sels.length > v.s.length-2) return ctx.throwError(ast, "Too many selectors");
  526. for (let i=0; i<sels.length; i++) {
  527. if (sels[i] >= v.s[i] / v.s[i+1]) return ctx.throwError(ast, "Out of Range");
  528. if (sels[i] < 0 ) return ctx.throwError(ast, "selector negative");
  529. o += sels[i] * v.s[i+1];
  530. s = v.s[i+1];
  531. }
  532. if (v.t == "V") {
  533. return {
  534. t: "V",
  535. s: v.s.slice(sels.length),
  536. v: v.v.slice(o, o+s)
  537. };
  538. } else if (v.t == "S") {
  539. return {
  540. t: "S",
  541. s: v.s.slice(sels.length),
  542. sIdx: o + v.sIdx
  543. };
  544. } else if (v.t == "C") {
  545. return {
  546. t: "C",
  547. s: v.s.slice(sels.length),
  548. cIdx: o
  549. };
  550. } else {
  551. assert(false);
  552. }
  553. }
  554. function execPin(ctx, ast) {
  555. const selsC = [];
  556. for (let i=0; i< ast.component.selectors.length; i++) {
  557. const sel = exec(ctx, ast.component.selectors[i]);
  558. if (ctx.error) return;
  559. if (sel.s[0] != 1) return ctx.throwError(ast, "Component selector cannot be an array");
  560. if (sel.v[0].t != "N") return NQVAL;
  561. selsC.push(Scalar.toNumber(sel.v[0].v));
  562. }
  563. const cIdx = ctx.getComponentIdx(ast.component.name, selsC);
  564. if (cIdx<0) return ctx.throwError(ast.component, "Component does not exists: "+ast.component.name);
  565. const selsP = [];
  566. for (let i=0; i< ast.pin.selectors.length; i++) {
  567. const sel = exec(ctx, ast.pin.selectors[i]);
  568. if (ctx.error) return;
  569. if (sel.s[0] != 1) return ctx.throwError(ast, "Signal selector cannot be an array");
  570. if (sel.v[0].t != "N") return NQVAL;
  571. selsP.push(Scalar.toNumber(sel.v[0].v));
  572. }
  573. const sIdx = ctx.components[cIdx].names.getSignalIdx(ast.pin.name, selsP);
  574. if (sIdx<0) return ctx.throwError(ast, "Signal not defined:" + buildFullName() );
  575. return {
  576. t: "S",
  577. sIdx: sIdx,
  578. s: utils.accSizes(ctx.components[cIdx].names.o[ast.pin.name].sizes).slice(selsP.length)
  579. };
  580. function buildFullName() {
  581. return ast.component.name + sels2str(selsC) + "." + ast.pin.name + sels2str(selsP);
  582. }
  583. function sels2str(sels) {
  584. let S = "";
  585. for (let i=0; i< sels.length; i++) {
  586. S += "[" + sels[i] + "]";
  587. }
  588. return S;
  589. }
  590. }
  591. function execLoop(ctx, ast) {
  592. if (ast.init) {
  593. exec(ctx, ast.init);
  594. if (ctx.error) return;
  595. }
  596. let v = exec(ctx, ast.condition);
  597. if (ctx.error) return;
  598. if (v.s[0] != 1) return ctx.throwError(ast.condition, "Condition in loop cannot be an array");
  599. if (v.v[0].t != "N") {
  600. iterateAST(ast, (ast) => {
  601. if (ast.type == "OP") {
  602. if (["==>", "<==", "==="].indexOf(ast.op) >= 0) {
  603. return ctx.throwError(ast.condition, "Constraint inside a calculating block");
  604. }
  605. }
  606. });
  607. // Assert no constraints
  608. return;
  609. }
  610. while ((! ctx.F.isZero(v.v[0].v))&&(!ctx.returnValue)) {
  611. exec(ctx, ast.body);
  612. if (ctx.error) return;
  613. if (ast.step) {
  614. exec(ctx, ast.step);
  615. if (ctx.error) return;
  616. }
  617. v = exec(ctx, ast.condition);
  618. if (ctx.error) return;
  619. if (v.s[0] != 1) return ctx.throwError(ast.condition, "Condition in loop cannot be an array");
  620. if (v.v[0].t != "N") return ctx.throwError(ast.condition, "Condition result not a number");
  621. }
  622. }
  623. function execCompute(ctx, ast) {
  624. iterateAST(ast, (ast) => {
  625. if (ast.type == "OP") {
  626. if (["==>", "<==", "==="].indexOf(ast.op) >= 0) {
  627. return ctx.throwError(ast.condition, "Constraint inside a calculating block");
  628. }
  629. }
  630. });
  631. }
  632. function execIf(ctx, ast) {
  633. let v = exec(ctx, ast.condition);
  634. if (ctx.error) return;
  635. if (v.s[0] != 1) return ctx.throwError(ast.condition, "Condition cannot be an array");
  636. if (v.v[0].t != "N") {
  637. iterateAST(ast, (ast) => {
  638. if (ast.type == "OP") {
  639. if (["==>", "<==", "==="].indexOf(ast.op) >= 0) {
  640. return ctx.throwError(ast.condition, "Constraint inside a calculating block");
  641. }
  642. }
  643. });
  644. // Assert no constraints
  645. return;
  646. }
  647. if (!ctx.F.isZero(v.v[0].v)) {
  648. exec(ctx, ast.then);
  649. } else {
  650. if (ast.else) {
  651. exec(ctx, ast.else);
  652. }
  653. }
  654. }
  655. function execTerCon(ctx, ast) {
  656. let v = exec(ctx, ast.values[0]);
  657. if (ctx.error) return;
  658. if (v.s[0] != 1) return ctx.throwError(ast.condition, "Condition cannot be an array");
  659. if (v.v[0].t != "N") {
  660. iterateAST(ast, (ast) => {
  661. if (ast.type == "OP") {
  662. if (["==>", "<==", "==="].indexOf(ast.op) >= 0) {
  663. return ctx.throwError(ast.condition, "Constraint inside a calculating block");
  664. }
  665. }
  666. });
  667. // Assert no constraints
  668. return NQVAL;
  669. }
  670. if (!ctx.F.isZero(v.v[0].v)) {
  671. return exec(ctx, ast.values[1]);
  672. } else {
  673. return exec(ctx, ast.values[2]);
  674. }
  675. }
  676. function execOp(ctx, ast, op, nOps) {
  677. const operands = [];
  678. for (let i=0; i<nOps; i++) {
  679. const a = exec(ctx, ast.values[i]);
  680. if (ctx.error) return;
  681. const aV = val(ctx, a, ast.values[i]);
  682. operands.push(aV);
  683. }
  684. return {
  685. t: "V",
  686. s: [1,0],
  687. v: [ctx.lc[op](...operands)]
  688. };
  689. }
  690. function execOpOp(ctx, ast, op, lr) {
  691. if (ast.values[0].type != "VARIABLE") return ctx.throwError(ast, "incrementing a non variable");
  692. if (!utils.isDefined(ast.values[0].refId)) return ctx.throwError(ast, "Assigning to a non variable");
  693. const left = ctx.refs[ast.values[0].refId];
  694. if (left.t != "V") return ctx.throwError(ast, `Only variables can use ${ast.op} operations`);
  695. let leftSels = [];
  696. if (ast.values[0].selectors) {
  697. for (let i=0; i< ast.values[0].selectors.length; i++) {
  698. const sel = exec(ctx, ast.values[0].selectors[i]);
  699. if (ctx.error) return;
  700. if (sel.s[0] != 1) return ctx.throwError(ast, "Selector cannot be an array");
  701. if (sel.v[0].t != "N") return {t: "NQ"};
  702. leftSels.push( Scalar.toNumber(sel.v[0].v) );
  703. }
  704. }
  705. if (!left.s) return ctx.throwError(ast, "variable. not defined yet");
  706. let o = 0;
  707. let s = left.s[0];
  708. for (let i=0; i<leftSels.length; i++) {
  709. o += leftSels[i]*left.s[i+1];
  710. s = left.s[i+1];
  711. }
  712. if (s != 1) return ctx.throwError(ast, `invalid operator ${ast.op} in an array`);
  713. const resBefore = left.v[o];
  714. let right;
  715. if (ast.values[1]) {
  716. const rightRef = exec(ctx, ast.values[1]);
  717. if (ctx.error) return;
  718. right = val(ctx, rightRef);
  719. } else {
  720. right = {t:"N", v: ctx.F.one};
  721. }
  722. if (!right) return ctx.throwError(ast, "adding a no number");
  723. const resAfter = ctx.lc[op](resBefore, right);
  724. left.v[o] = resAfter;
  725. if (lr == "RIGHT") {
  726. return {
  727. t: "V",
  728. s: [1,0],
  729. v: [resBefore]
  730. };
  731. } else {
  732. return {
  733. t: "V",
  734. s: [1,0],
  735. v: [resAfter]
  736. };
  737. }
  738. }
  739. // Extract the value of a reference.
  740. // Must be a single value. (cannot be an array)
  741. // The result is an LCAlgebra compatible object {t: ["N"|"LC"|"QEX"|"NQ"], [coefs|v|a,b,c]}
  742. function val(ctx, a, ast) {
  743. if (a.s[0] != 1) return ctx.throwError(ast, "Array not allowed");
  744. if (a.t=="V") {
  745. return a.v[0];
  746. } else if (a.t=="S") {
  747. const res = {
  748. t: "LC",
  749. coefs: {}
  750. };
  751. let sIdx = a.sIdx;
  752. while (ctx.signals[sIdx].e >= 0) sIdx = ctx.signals[sIdx].e;
  753. res.coefs[sIdx] = ctx.F.one;
  754. return res;
  755. } else {
  756. ctx.throwError(ast, "Invalid type: " + a.t);
  757. }
  758. }
  759. function execConstrain(ctx, ast) {
  760. ast.fileName = ctx.fileName;
  761. ast.filePath = ctx.filePath;
  762. const a = exec(ctx, ast.values[0]);
  763. if (ctx.error) return;
  764. const aV = val(ctx, a, ast.values[0]);
  765. const b = exec(ctx, ast.values[1]);
  766. if (ctx.error) return;
  767. const bV = val(ctx, b, ast.values[1]);
  768. const res = ctx.lc.sub(aV,bV);
  769. if (res.type == "NQ") return ctx.throwError(ast, "Non Quadratic constraint");
  770. if (!ctx.lc.isZero(res)) {
  771. ctx.constraints.push(ctx.lc.toQEX(res));
  772. if (ctx.verbose) {
  773. if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length);
  774. }
  775. }
  776. return a;
  777. }
  778. function execSignalAssignConstrain(ctx, ast) {
  779. const v = execAssignement(ctx,ast);
  780. if (ctx.error) return;
  781. execConstrain(ctx, ast);
  782. if (ctx.error) return;
  783. return v;
  784. }
  785. function execInclude(ctx, ast) {
  786. if (ast.block) {
  787. const oldFilePath = ctx.filePath;
  788. const oldFileName = ctx.fileName;
  789. ctx.filePath = ast.filePath;
  790. ctx.fileName = ast.fileName;
  791. exec(ctx, ast.block); // Process only one.
  792. ctx.filePath = oldFilePath;
  793. ctx.fileName = oldFileName;
  794. }
  795. }
  796. function execArray(ctx, ast) {
  797. const res = {t: "V", v:[]};
  798. let subSize = null;
  799. for (let i=0; i<ast.values.length; i++) {
  800. const e = exec(ctx, ast.values[i]);
  801. if (i==0) {
  802. subSize=e.s;
  803. } else {
  804. if (!utils.sameSizes(subSize, e.s)) return ctx.throwError(ast, "Array mus be homogeneous");
  805. }
  806. if (e.t == "V") {
  807. for (let j=0; j<e.v.length;j++) res.v.push(e.v[j]);
  808. } else if (e.t == "S") {
  809. for (let j=0; j<e.v.length;j++) {
  810. const sv = {t: "LC", coefs: {}};
  811. sv.coefs[e.sIdx+j] = ctx.F.one;
  812. res.v.push(sv);
  813. }
  814. } else {
  815. return ctx.throwError(ast, "Type not allowed in array");
  816. }
  817. }
  818. res.s = [ast.values.length*subSize[0], ...subSize];
  819. return res;
  820. }
  821. function createRefs(ctx, ast, scope) {
  822. const scopeLabels = [];
  823. const scopes = scope ? [scope] : [{}];
  824. iterateAST(ast, (ast, level) => {
  825. while ((scopeLabels.length>0)&&(!level.startsWith(scopeLabels[scopeLabels.length-1]))) {
  826. scopes.pop();
  827. scopeLabels.pop();
  828. }
  829. if (ast.type == "DECLARE") {
  830. if (ast.declareType == "COMPONENT") {
  831. ast.refId = define(ast.name.name, {t: "C"});
  832. } else if ((ast.declareType == "SIGNALIN")||
  833. (ast.declareType == "SIGNALOUT")||
  834. (ast.declareType == "SIGNAL")) {
  835. ast.refId = define(ast.name.name, {t: "S"});
  836. } else if (ast.declareType == "VARIABLE") {
  837. ast.refId = define(ast.name.name, {t: "V", s: null});
  838. } else {
  839. return ctx.throwError(ast, "Invalid declaration: " + ast.declareType);
  840. }
  841. } else if (["BLOCK", "FOR", "IF", "WHILE", "COMPUTE"].indexOf(ast.type) >= 0) {
  842. scopeLabels.push(level);
  843. scopes.push({});
  844. } else if (ast.type == "TEMPLATEDEF") {
  845. ast.refId = define(ast.name, {t: "T"});
  846. } else if (ast.type == "FUNCTIONDEF") {
  847. ast.refId = define(ast.name, {t: "F"});
  848. } else if (ast.type == "INCLUDE") {
  849. const incFileName = path.resolve(ctx.filePath, ast.file);
  850. const incFilePath = path.dirname(incFileName);
  851. ctx.includedFiles = ctx.includedFiles || [];
  852. if (ctx.includedFiles[incFileName]) {
  853. ctx.bloc = null; // Include already included...
  854. return;
  855. }
  856. const src = fs.readFileSync(incFileName, "utf8");
  857. if (!src) return ctx.throwError(ast, "Include file not found: "+incFileName);
  858. ctx.includedFiles[incFileName] = src.split("\n");
  859. ast.block = parser.parse(src);
  860. ast.filePath = incFilePath;
  861. ast.fileName = incFileName;
  862. const oldFilePath = ctx.filePath;
  863. const oldFileName = ctx.fileName;
  864. ctx.filePath = incFilePath;
  865. ctx.fileName = incFileName;
  866. scopes.push({});
  867. createRefs(ctx, ast.block);
  868. scopes.pop();
  869. ctx.filePath = oldFilePath;
  870. ctx.fileName = oldFileName;
  871. } else if (ast.type == "VARIABLE") {
  872. ast.refId = name2ref(ast.name);
  873. }
  874. function define(name, entry) {
  875. if (scopes[scopes.length-1][name]) return ctx.throwError(ast, `Name already defined: ${name}`);
  876. for (let i=scopes.length-2; i>=0; i--) {
  877. if (scopes[i][name]) ctx.logWarning(ast, `Shadowing variable: ${name}`);
  878. }
  879. const refId = ctx.refs.length;
  880. entry.refId = refId;
  881. ctx.refs.push(entry);
  882. scopes[scopes.length-1][name] = refId;
  883. return refId;
  884. }
  885. function name2ref(n) {
  886. for (let i=scopes.length-1; i>=0; i--) {
  887. if (typeof scopes[i][n] !== "undefined") return scopes[i][n];
  888. }
  889. return -1;
  890. }
  891. });
  892. }