index.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.or = exports.and = exports.not = exports.CodeGen = exports.operators = exports.varKinds = exports.ValueScopeName = exports.ValueScope = exports.Scope = exports.Name = exports.regexpCode = exports.stringify = exports.getProperty = exports.nil = exports.strConcat = exports.str = exports._ = void 0;
  4. const code_1 = require("./code");
  5. const scope_1 = require("./scope");
  6. var code_2 = require("./code");
  7. Object.defineProperty(exports, "_", { enumerable: true, get: function () { return code_2._; } });
  8. Object.defineProperty(exports, "str", { enumerable: true, get: function () { return code_2.str; } });
  9. Object.defineProperty(exports, "strConcat", { enumerable: true, get: function () { return code_2.strConcat; } });
  10. Object.defineProperty(exports, "nil", { enumerable: true, get: function () { return code_2.nil; } });
  11. Object.defineProperty(exports, "getProperty", { enumerable: true, get: function () { return code_2.getProperty; } });
  12. Object.defineProperty(exports, "stringify", { enumerable: true, get: function () { return code_2.stringify; } });
  13. Object.defineProperty(exports, "regexpCode", { enumerable: true, get: function () { return code_2.regexpCode; } });
  14. Object.defineProperty(exports, "Name", { enumerable: true, get: function () { return code_2.Name; } });
  15. var scope_2 = require("./scope");
  16. Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return scope_2.Scope; } });
  17. Object.defineProperty(exports, "ValueScope", { enumerable: true, get: function () { return scope_2.ValueScope; } });
  18. Object.defineProperty(exports, "ValueScopeName", { enumerable: true, get: function () { return scope_2.ValueScopeName; } });
  19. Object.defineProperty(exports, "varKinds", { enumerable: true, get: function () { return scope_2.varKinds; } });
  20. exports.operators = {
  21. GT: new code_1._Code(">"),
  22. GTE: new code_1._Code(">="),
  23. LT: new code_1._Code("<"),
  24. LTE: new code_1._Code("<="),
  25. EQ: new code_1._Code("==="),
  26. NEQ: new code_1._Code("!=="),
  27. NOT: new code_1._Code("!"),
  28. OR: new code_1._Code("||"),
  29. AND: new code_1._Code("&&"),
  30. ADD: new code_1._Code("+"),
  31. };
  32. class Node {
  33. optimizeNodes() {
  34. return this;
  35. }
  36. optimizeNames(_names, _constants) {
  37. return this;
  38. }
  39. }
  40. class Def extends Node {
  41. constructor(varKind, name, rhs) {
  42. super();
  43. this.varKind = varKind;
  44. this.name = name;
  45. this.rhs = rhs;
  46. }
  47. render({ es5, _n }) {
  48. const varKind = es5 ? scope_1.varKinds.var : this.varKind;
  49. const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
  50. return `${varKind} ${this.name}${rhs};` + _n;
  51. }
  52. optimizeNames(names, constants) {
  53. if (!names[this.name.str])
  54. return;
  55. if (this.rhs)
  56. this.rhs = optimizeExpr(this.rhs, names, constants);
  57. return this;
  58. }
  59. get names() {
  60. return this.rhs instanceof code_1._CodeOrName ? this.rhs.names : {};
  61. }
  62. }
  63. class Assign extends Node {
  64. constructor(lhs, rhs, sideEffects) {
  65. super();
  66. this.lhs = lhs;
  67. this.rhs = rhs;
  68. this.sideEffects = sideEffects;
  69. }
  70. render({ _n }) {
  71. return `${this.lhs} = ${this.rhs};` + _n;
  72. }
  73. optimizeNames(names, constants) {
  74. if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
  75. return;
  76. this.rhs = optimizeExpr(this.rhs, names, constants);
  77. return this;
  78. }
  79. get names() {
  80. const names = this.lhs instanceof code_1.Name ? {} : { ...this.lhs.names };
  81. return addExprNames(names, this.rhs);
  82. }
  83. }
  84. class AssignOp extends Assign {
  85. constructor(lhs, op, rhs, sideEffects) {
  86. super(lhs, rhs, sideEffects);
  87. this.op = op;
  88. }
  89. render({ _n }) {
  90. return `${this.lhs} ${this.op}= ${this.rhs};` + _n;
  91. }
  92. }
  93. class Label extends Node {
  94. constructor(label) {
  95. super();
  96. this.label = label;
  97. this.names = {};
  98. }
  99. render({ _n }) {
  100. return `${this.label}:` + _n;
  101. }
  102. }
  103. class Break extends Node {
  104. constructor(label) {
  105. super();
  106. this.label = label;
  107. this.names = {};
  108. }
  109. render({ _n }) {
  110. const label = this.label ? ` ${this.label}` : "";
  111. return `break${label};` + _n;
  112. }
  113. }
  114. class Throw extends Node {
  115. constructor(error) {
  116. super();
  117. this.error = error;
  118. }
  119. render({ _n }) {
  120. return `throw ${this.error};` + _n;
  121. }
  122. get names() {
  123. return this.error.names;
  124. }
  125. }
  126. class AnyCode extends Node {
  127. constructor(code) {
  128. super();
  129. this.code = code;
  130. }
  131. render({ _n }) {
  132. return `${this.code};` + _n;
  133. }
  134. optimizeNodes() {
  135. return `${this.code}` ? this : undefined;
  136. }
  137. optimizeNames(names, constants) {
  138. this.code = optimizeExpr(this.code, names, constants);
  139. return this;
  140. }
  141. get names() {
  142. return this.code instanceof code_1._CodeOrName ? this.code.names : {};
  143. }
  144. }
  145. class ParentNode extends Node {
  146. constructor(nodes = []) {
  147. super();
  148. this.nodes = nodes;
  149. }
  150. render(opts) {
  151. return this.nodes.reduce((code, n) => code + n.render(opts), "");
  152. }
  153. optimizeNodes() {
  154. const { nodes } = this;
  155. let i = nodes.length;
  156. while (i--) {
  157. const n = nodes[i].optimizeNodes();
  158. if (Array.isArray(n))
  159. nodes.splice(i, 1, ...n);
  160. else if (n)
  161. nodes[i] = n;
  162. else
  163. nodes.splice(i, 1);
  164. }
  165. return nodes.length > 0 ? this : undefined;
  166. }
  167. optimizeNames(names, constants) {
  168. const { nodes } = this;
  169. let i = nodes.length;
  170. while (i--) {
  171. // iterating backwards improves 1-pass optimization
  172. const n = nodes[i];
  173. if (n.optimizeNames(names, constants))
  174. continue;
  175. subtractNames(names, n.names);
  176. nodes.splice(i, 1);
  177. }
  178. return nodes.length > 0 ? this : undefined;
  179. }
  180. get names() {
  181. return this.nodes.reduce((names, n) => addNames(names, n.names), {});
  182. }
  183. }
  184. class BlockNode extends ParentNode {
  185. render(opts) {
  186. return "{" + opts._n + super.render(opts) + "}" + opts._n;
  187. }
  188. }
  189. class Root extends ParentNode {
  190. }
  191. class Else extends BlockNode {
  192. }
  193. Else.kind = "else";
  194. class If extends BlockNode {
  195. constructor(condition, nodes) {
  196. super(nodes);
  197. this.condition = condition;
  198. }
  199. render(opts) {
  200. let code = `if(${this.condition})` + super.render(opts);
  201. if (this.else)
  202. code += "else " + this.else.render(opts);
  203. return code;
  204. }
  205. optimizeNodes() {
  206. super.optimizeNodes();
  207. const cond = this.condition;
  208. if (cond === true)
  209. return this.nodes; // else is ignored here
  210. let e = this.else;
  211. if (e) {
  212. const ns = e.optimizeNodes();
  213. e = this.else = Array.isArray(ns) ? new Else(ns) : ns;
  214. }
  215. if (e) {
  216. if (cond === false)
  217. return e instanceof If ? e : e.nodes;
  218. if (this.nodes.length)
  219. return this;
  220. return new If(not(cond), e instanceof If ? [e] : e.nodes);
  221. }
  222. if (cond === false || !this.nodes.length)
  223. return undefined;
  224. return this;
  225. }
  226. optimizeNames(names, constants) {
  227. var _a;
  228. this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
  229. if (!(super.optimizeNames(names, constants) || this.else))
  230. return;
  231. this.condition = optimizeExpr(this.condition, names, constants);
  232. return this;
  233. }
  234. get names() {
  235. const names = super.names;
  236. addExprNames(names, this.condition);
  237. if (this.else)
  238. addNames(names, this.else.names);
  239. return names;
  240. }
  241. }
  242. If.kind = "if";
  243. class For extends BlockNode {
  244. }
  245. For.kind = "for";
  246. class ForLoop extends For {
  247. constructor(iteration) {
  248. super();
  249. this.iteration = iteration;
  250. }
  251. render(opts) {
  252. return `for(${this.iteration})` + super.render(opts);
  253. }
  254. optimizeNames(names, constants) {
  255. if (!super.optimizeNames(names, constants))
  256. return;
  257. this.iteration = optimizeExpr(this.iteration, names, constants);
  258. return this;
  259. }
  260. get names() {
  261. return addNames(super.names, this.iteration.names);
  262. }
  263. }
  264. class ForRange extends For {
  265. constructor(varKind, name, from, to) {
  266. super();
  267. this.varKind = varKind;
  268. this.name = name;
  269. this.from = from;
  270. this.to = to;
  271. }
  272. render(opts) {
  273. const varKind = opts.es5 ? scope_1.varKinds.var : this.varKind;
  274. const { name, from, to } = this;
  275. return `for(${varKind} ${name}=${from}; ${name}<${to}; ${name}++)` + super.render(opts);
  276. }
  277. get names() {
  278. const names = addExprNames(super.names, this.from);
  279. return addExprNames(names, this.to);
  280. }
  281. }
  282. class ForIter extends For {
  283. constructor(loop, varKind, name, iterable) {
  284. super();
  285. this.loop = loop;
  286. this.varKind = varKind;
  287. this.name = name;
  288. this.iterable = iterable;
  289. }
  290. render(opts) {
  291. return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
  292. }
  293. optimizeNames(names, constants) {
  294. if (!super.optimizeNames(names, constants))
  295. return;
  296. this.iterable = optimizeExpr(this.iterable, names, constants);
  297. return this;
  298. }
  299. get names() {
  300. return addNames(super.names, this.iterable.names);
  301. }
  302. }
  303. class Func extends BlockNode {
  304. constructor(name, args, async) {
  305. super();
  306. this.name = name;
  307. this.args = args;
  308. this.async = async;
  309. }
  310. render(opts) {
  311. const _async = this.async ? "async " : "";
  312. return `${_async}function ${this.name}(${this.args})` + super.render(opts);
  313. }
  314. }
  315. Func.kind = "func";
  316. class Return extends ParentNode {
  317. render(opts) {
  318. return "return " + super.render(opts);
  319. }
  320. }
  321. Return.kind = "return";
  322. class Try extends BlockNode {
  323. render(opts) {
  324. let code = "try" + super.render(opts);
  325. if (this.catch)
  326. code += this.catch.render(opts);
  327. if (this.finally)
  328. code += this.finally.render(opts);
  329. return code;
  330. }
  331. optimizeNodes() {
  332. var _a, _b;
  333. super.optimizeNodes();
  334. (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNodes();
  335. (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
  336. return this;
  337. }
  338. optimizeNames(names, constants) {
  339. var _a, _b;
  340. super.optimizeNames(names, constants);
  341. (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
  342. (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants);
  343. return this;
  344. }
  345. get names() {
  346. const names = super.names;
  347. if (this.catch)
  348. addNames(names, this.catch.names);
  349. if (this.finally)
  350. addNames(names, this.finally.names);
  351. return names;
  352. }
  353. }
  354. class Catch extends BlockNode {
  355. constructor(error) {
  356. super();
  357. this.error = error;
  358. }
  359. render(opts) {
  360. return `catch(${this.error})` + super.render(opts);
  361. }
  362. }
  363. Catch.kind = "catch";
  364. class Finally extends BlockNode {
  365. render(opts) {
  366. return "finally" + super.render(opts);
  367. }
  368. }
  369. Finally.kind = "finally";
  370. class CodeGen {
  371. constructor(extScope, opts = {}) {
  372. this._values = {};
  373. this._blockStarts = [];
  374. this._constants = {};
  375. this.opts = { ...opts, _n: opts.lines ? "\n" : "" };
  376. this._extScope = extScope;
  377. this._scope = new scope_1.Scope({ parent: extScope });
  378. this._nodes = [new Root()];
  379. }
  380. toString() {
  381. return this._root.render(this.opts);
  382. }
  383. // returns unique name in the internal scope
  384. name(prefix) {
  385. return this._scope.name(prefix);
  386. }
  387. // reserves unique name in the external scope
  388. scopeName(prefix) {
  389. return this._extScope.name(prefix);
  390. }
  391. // reserves unique name in the external scope and assigns value to it
  392. scopeValue(prefixOrName, value) {
  393. const name = this._extScope.value(prefixOrName, value);
  394. const vs = this._values[name.prefix] || (this._values[name.prefix] = new Set());
  395. vs.add(name);
  396. return name;
  397. }
  398. getScopeValue(prefix, keyOrRef) {
  399. return this._extScope.getValue(prefix, keyOrRef);
  400. }
  401. // return code that assigns values in the external scope to the names that are used internally
  402. // (same names that were returned by gen.scopeName or gen.scopeValue)
  403. scopeRefs(scopeName) {
  404. return this._extScope.scopeRefs(scopeName, this._values);
  405. }
  406. scopeCode() {
  407. return this._extScope.scopeCode(this._values);
  408. }
  409. _def(varKind, nameOrPrefix, rhs, constant) {
  410. const name = this._scope.toName(nameOrPrefix);
  411. if (rhs !== undefined && constant)
  412. this._constants[name.str] = rhs;
  413. this._leafNode(new Def(varKind, name, rhs));
  414. return name;
  415. }
  416. // `const` declaration (`var` in es5 mode)
  417. const(nameOrPrefix, rhs, _constant) {
  418. return this._def(scope_1.varKinds.const, nameOrPrefix, rhs, _constant);
  419. }
  420. // `let` declaration with optional assignment (`var` in es5 mode)
  421. let(nameOrPrefix, rhs, _constant) {
  422. return this._def(scope_1.varKinds.let, nameOrPrefix, rhs, _constant);
  423. }
  424. // `var` declaration with optional assignment
  425. var(nameOrPrefix, rhs, _constant) {
  426. return this._def(scope_1.varKinds.var, nameOrPrefix, rhs, _constant);
  427. }
  428. // assignment code
  429. assign(lhs, rhs, sideEffects) {
  430. return this._leafNode(new Assign(lhs, rhs, sideEffects));
  431. }
  432. // `+=` code
  433. add(lhs, rhs) {
  434. return this._leafNode(new AssignOp(lhs, exports.operators.ADD, rhs));
  435. }
  436. // appends passed SafeExpr to code or executes Block
  437. code(c) {
  438. if (typeof c == "function")
  439. c();
  440. else if (c !== code_1.nil)
  441. this._leafNode(new AnyCode(c));
  442. return this;
  443. }
  444. // returns code for object literal for the passed argument list of key-value pairs
  445. object(...keyValues) {
  446. const code = ["{"];
  447. for (const [key, value] of keyValues) {
  448. if (code.length > 1)
  449. code.push(",");
  450. code.push(key);
  451. if (key !== value || this.opts.es5) {
  452. code.push(":");
  453. (0, code_1.addCodeArg)(code, value);
  454. }
  455. }
  456. code.push("}");
  457. return new code_1._Code(code);
  458. }
  459. // `if` clause (or statement if `thenBody` and, optionally, `elseBody` are passed)
  460. if(condition, thenBody, elseBody) {
  461. this._blockNode(new If(condition));
  462. if (thenBody && elseBody) {
  463. this.code(thenBody).else().code(elseBody).endIf();
  464. }
  465. else if (thenBody) {
  466. this.code(thenBody).endIf();
  467. }
  468. else if (elseBody) {
  469. throw new Error('CodeGen: "else" body without "then" body');
  470. }
  471. return this;
  472. }
  473. // `else if` clause - invalid without `if` or after `else` clauses
  474. elseIf(condition) {
  475. return this._elseNode(new If(condition));
  476. }
  477. // `else` clause - only valid after `if` or `else if` clauses
  478. else() {
  479. return this._elseNode(new Else());
  480. }
  481. // end `if` statement (needed if gen.if was used only with condition)
  482. endIf() {
  483. return this._endBlockNode(If, Else);
  484. }
  485. _for(node, forBody) {
  486. this._blockNode(node);
  487. if (forBody)
  488. this.code(forBody).endFor();
  489. return this;
  490. }
  491. // a generic `for` clause (or statement if `forBody` is passed)
  492. for(iteration, forBody) {
  493. return this._for(new ForLoop(iteration), forBody);
  494. }
  495. // `for` statement for a range of values
  496. forRange(nameOrPrefix, from, to, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.let) {
  497. const name = this._scope.toName(nameOrPrefix);
  498. return this._for(new ForRange(varKind, name, from, to), () => forBody(name));
  499. }
  500. // `for-of` statement (in es5 mode replace with a normal for loop)
  501. forOf(nameOrPrefix, iterable, forBody, varKind = scope_1.varKinds.const) {
  502. const name = this._scope.toName(nameOrPrefix);
  503. if (this.opts.es5) {
  504. const arr = iterable instanceof code_1.Name ? iterable : this.var("_arr", iterable);
  505. return this.forRange("_i", 0, (0, code_1._) `${arr}.length`, (i) => {
  506. this.var(name, (0, code_1._) `${arr}[${i}]`);
  507. forBody(name);
  508. });
  509. }
  510. return this._for(new ForIter("of", varKind, name, iterable), () => forBody(name));
  511. }
  512. // `for-in` statement.
  513. // With option `ownProperties` replaced with a `for-of` loop for object keys
  514. forIn(nameOrPrefix, obj, forBody, varKind = this.opts.es5 ? scope_1.varKinds.var : scope_1.varKinds.const) {
  515. if (this.opts.ownProperties) {
  516. return this.forOf(nameOrPrefix, (0, code_1._) `Object.keys(${obj})`, forBody);
  517. }
  518. const name = this._scope.toName(nameOrPrefix);
  519. return this._for(new ForIter("in", varKind, name, obj), () => forBody(name));
  520. }
  521. // end `for` loop
  522. endFor() {
  523. return this._endBlockNode(For);
  524. }
  525. // `label` statement
  526. label(label) {
  527. return this._leafNode(new Label(label));
  528. }
  529. // `break` statement
  530. break(label) {
  531. return this._leafNode(new Break(label));
  532. }
  533. // `return` statement
  534. return(value) {
  535. const node = new Return();
  536. this._blockNode(node);
  537. this.code(value);
  538. if (node.nodes.length !== 1)
  539. throw new Error('CodeGen: "return" should have one node');
  540. return this._endBlockNode(Return);
  541. }
  542. // `try` statement
  543. try(tryBody, catchCode, finallyCode) {
  544. if (!catchCode && !finallyCode)
  545. throw new Error('CodeGen: "try" without "catch" and "finally"');
  546. const node = new Try();
  547. this._blockNode(node);
  548. this.code(tryBody);
  549. if (catchCode) {
  550. const error = this.name("e");
  551. this._currNode = node.catch = new Catch(error);
  552. catchCode(error);
  553. }
  554. if (finallyCode) {
  555. this._currNode = node.finally = new Finally();
  556. this.code(finallyCode);
  557. }
  558. return this._endBlockNode(Catch, Finally);
  559. }
  560. // `throw` statement
  561. throw(error) {
  562. return this._leafNode(new Throw(error));
  563. }
  564. // start self-balancing block
  565. block(body, nodeCount) {
  566. this._blockStarts.push(this._nodes.length);
  567. if (body)
  568. this.code(body).endBlock(nodeCount);
  569. return this;
  570. }
  571. // end the current self-balancing block
  572. endBlock(nodeCount) {
  573. const len = this._blockStarts.pop();
  574. if (len === undefined)
  575. throw new Error("CodeGen: not in self-balancing block");
  576. const toClose = this._nodes.length - len;
  577. if (toClose < 0 || (nodeCount !== undefined && toClose !== nodeCount)) {
  578. throw new Error(`CodeGen: wrong number of nodes: ${toClose} vs ${nodeCount} expected`);
  579. }
  580. this._nodes.length = len;
  581. return this;
  582. }
  583. // `function` heading (or definition if funcBody is passed)
  584. func(name, args = code_1.nil, async, funcBody) {
  585. this._blockNode(new Func(name, args, async));
  586. if (funcBody)
  587. this.code(funcBody).endFunc();
  588. return this;
  589. }
  590. // end function definition
  591. endFunc() {
  592. return this._endBlockNode(Func);
  593. }
  594. optimize(n = 1) {
  595. while (n-- > 0) {
  596. this._root.optimizeNodes();
  597. this._root.optimizeNames(this._root.names, this._constants);
  598. }
  599. }
  600. _leafNode(node) {
  601. this._currNode.nodes.push(node);
  602. return this;
  603. }
  604. _blockNode(node) {
  605. this._currNode.nodes.push(node);
  606. this._nodes.push(node);
  607. }
  608. _endBlockNode(N1, N2) {
  609. const n = this._currNode;
  610. if (n instanceof N1 || (N2 && n instanceof N2)) {
  611. this._nodes.pop();
  612. return this;
  613. }
  614. throw new Error(`CodeGen: not in block "${N2 ? `${N1.kind}/${N2.kind}` : N1.kind}"`);
  615. }
  616. _elseNode(node) {
  617. const n = this._currNode;
  618. if (!(n instanceof If)) {
  619. throw new Error('CodeGen: "else" without "if"');
  620. }
  621. this._currNode = n.else = node;
  622. return this;
  623. }
  624. get _root() {
  625. return this._nodes[0];
  626. }
  627. get _currNode() {
  628. const ns = this._nodes;
  629. return ns[ns.length - 1];
  630. }
  631. set _currNode(node) {
  632. const ns = this._nodes;
  633. ns[ns.length - 1] = node;
  634. }
  635. }
  636. exports.CodeGen = CodeGen;
  637. function addNames(names, from) {
  638. for (const n in from)
  639. names[n] = (names[n] || 0) + (from[n] || 0);
  640. return names;
  641. }
  642. function addExprNames(names, from) {
  643. return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
  644. }
  645. function optimizeExpr(expr, names, constants) {
  646. if (expr instanceof code_1.Name)
  647. return replaceName(expr);
  648. if (!canOptimize(expr))
  649. return expr;
  650. return new code_1._Code(expr._items.reduce((items, c) => {
  651. if (c instanceof code_1.Name)
  652. c = replaceName(c);
  653. if (c instanceof code_1._Code)
  654. items.push(...c._items);
  655. else
  656. items.push(c);
  657. return items;
  658. }, []));
  659. function replaceName(n) {
  660. const c = constants[n.str];
  661. if (c === undefined || names[n.str] !== 1)
  662. return n;
  663. delete names[n.str];
  664. return c;
  665. }
  666. function canOptimize(e) {
  667. return (e instanceof code_1._Code &&
  668. e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants[c.str] !== undefined));
  669. }
  670. }
  671. function subtractNames(names, from) {
  672. for (const n in from)
  673. names[n] = (names[n] || 0) - (from[n] || 0);
  674. }
  675. function not(x) {
  676. return typeof x == "boolean" || typeof x == "number" || x === null ? !x : (0, code_1._) `!${par(x)}`;
  677. }
  678. exports.not = not;
  679. const andCode = mappend(exports.operators.AND);
  680. // boolean AND (&&) expression with the passed arguments
  681. function and(...args) {
  682. return args.reduce(andCode);
  683. }
  684. exports.and = and;
  685. const orCode = mappend(exports.operators.OR);
  686. // boolean OR (||) expression with the passed arguments
  687. function or(...args) {
  688. return args.reduce(orCode);
  689. }
  690. exports.or = or;
  691. function mappend(op) {
  692. return (x, y) => (x === code_1.nil ? y : y === code_1.nil ? x : (0, code_1._) `${par(x)} ${op} ${par(y)}`);
  693. }
  694. function par(x) {
  695. return x instanceof code_1.Name ? x : (0, code_1._) `(${x})`;
  696. }
  697. //# sourceMappingURL=index.js.map