Advertisement
Guest User

blagoipidor.js

a guest
Mar 24th, 2019
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.11 KB | None | 0 0
  1. "use strict";
  2.  
  3. let expressions = (function () {
  4. function myNew(constructor, args) {
  5. let instance = Object.create(constructor.prototype);
  6. constructor.apply(instance, args);
  7. return instance;
  8. }
  9.  
  10. let VARS = {
  11. 'x': 0,
  12. 'y': 1,
  13. 'z': 2
  14. };
  15. let OPS = {};
  16.  
  17.  
  18. let Primitive = function () {
  19. this.prefix = function () {
  20. return '' + this.value;
  21. };
  22. this.postfix = function () {
  23. return '' + this.value;
  24. };
  25. this.toString = function () {
  26. return '' + this.value;
  27. };
  28. };
  29. let Const = function (value) {
  30. this.value = value;
  31. };
  32. Const.prototype = new Primitive();
  33. Const.prototype.evaluate = function () {
  34. return this.value;
  35. };
  36. Const.prototype.diff = function () {
  37. return Const.ZERO;
  38. };
  39.  
  40. Const.ZERO = new Const(0);
  41. Const.ONE = new Const(1);
  42. Const.TWO = new Const(2);
  43.  
  44. let Variable = function (name) {
  45. this.value = name;
  46. this.index = VARS[this.value];
  47. };
  48. Variable.prototype = new Primitive();
  49. Variable.prototype.evaluate = function () {
  50. return arguments[this.index];
  51. };
  52. Variable.prototype.diff = function (name) {
  53. return name === this.value ? Const.ONE : Const.ZERO;
  54. };
  55.  
  56. let Creator = function () {
  57. this.requested = {};
  58.  
  59. this.get = function (name) {
  60. if (!(name in this.requested)) {
  61. this.requested[name] = new Variable(name);
  62. }
  63. return this.requested[name];
  64. }
  65. };
  66. let variableCreator = new Creator();
  67.  
  68. let AbstractOperator = function (symbol, operation, derivative) {
  69. this.op = function (index) {
  70. return this.operands[index];
  71. };
  72.  
  73. this.prefix = function () {
  74. return '(' + symbol + ' ' + this.operands.map(function (elem) {
  75. return elem.prefix();
  76. }).join(' ') + ')';
  77. };
  78. this.postfix = function () {
  79. return '(' + this.operands.map(function (elem) {
  80. return elem.postfix()
  81. }).join(' ') + ' ' + symbol + ')';
  82. };
  83. this.toString = function () {
  84. return this.operands.join(' ') + ' ' + symbol;
  85. };
  86. this.evaluate = function () {
  87. let args = arguments;
  88. return operation(...this.operands.map(function (elem) {
  89. return elem.evaluate.apply(elem, args);
  90. }));
  91. };
  92. this.diff = function (name) {
  93. return derivative.call(this, name);
  94. };
  95. };
  96.  
  97. let operatorFactory = function (symbol, operation, derivative) {
  98. let Operator = function () {
  99. this.operands = [].slice.call(arguments);
  100. };
  101. Operator.prototype = new AbstractOperator(symbol, operation, derivative);
  102.  
  103. OPS[symbol] = {
  104. op: Operator,
  105. opCount: operation.length
  106. };
  107. return Operator;
  108. };
  109.  
  110. let ArcTan = operatorFactory(
  111. 'atan',
  112. function (a) {
  113. return Math.atan(a);
  114. },
  115. function (name) {
  116. return new Multiply(
  117. new Divide(
  118. Const.ONE,
  119. new Add(
  120. new Multiply(this.op(0), this.op(0)),
  121. Const.ONE
  122. )
  123. ),
  124. this.op(0).diff(name)
  125. );
  126. }
  127. );
  128.  
  129. let Exp = operatorFactory(
  130. 'exp',
  131. function (a) {
  132. return Math.exp(a);
  133. },
  134. function (name) {
  135. return new Multiply(
  136. this,
  137. this.op(0).diff(name)
  138. );
  139. }
  140. );
  141.  
  142. let Negate = operatorFactory(
  143. 'negate',
  144. function (a) {
  145. return -a;
  146. },
  147. function (name) {
  148. return new Negate(this.op(0).diff(name));
  149. }
  150. );
  151.  
  152. let Square = operatorFactory(
  153. 'square',
  154. function (a) {
  155. return a * a;
  156. },
  157. function (name) {
  158. return new Multiply(
  159. Const.TWO,
  160. new Multiply(this.op(0), this.op(0).diff(name))
  161. );
  162. }
  163. );
  164.  
  165. let Sqrt = operatorFactory(
  166. 'sqrt',
  167. function (a) {
  168. return Math.pow(Math.abs(a), 0.5);
  169. },
  170. function (name) {
  171. return new Divide(
  172. new Multiply(this.op(0).diff(name), this.op(0)),
  173. new Multiply(
  174. Const.TWO,
  175. new Sqrt(new Multiply(
  176. this.op(0),
  177. new Multiply(this.op(0), this.op(0)))
  178. )
  179. )
  180. );
  181. }
  182. );
  183.  
  184. let Add = operatorFactory(
  185. '+',
  186. function (a, b) {
  187. return a + b;
  188. },
  189. function (name) {
  190. return new Add(this.op(0).diff(name), this.op(1).diff(name));
  191. }
  192. );
  193.  
  194. let Subtract = operatorFactory(
  195. '-',
  196. function (a, b) {
  197. return a - b;
  198. },
  199. function (name) {
  200. return new Subtract(this.op(0).diff(name), this.op(1).diff(name));
  201. }
  202. );
  203.  
  204. let Multiply = operatorFactory(
  205. '*',
  206. function (a, b) {
  207. return a * b;
  208. },
  209. function (name) {
  210. return new Add(
  211. new Multiply(this.op(0), this.op(1).diff(name)),
  212. new Multiply(this.op(0).diff(name), this.op(1))
  213. );
  214. }
  215. );
  216.  
  217. let Divide = operatorFactory(
  218. '/',
  219. function (a, b) {
  220. return a / b;
  221. },
  222. function (name) {
  223. return new Divide(
  224. new Subtract(
  225. new Multiply(this.op(0).diff(name), this.op(1)),
  226. new Multiply(this.op(0), this.op(1).diff(name))
  227. ),
  228. new Multiply(this.op(1), this.op(1))
  229. );
  230. }
  231. );
  232.  
  233. let parse = function (str) {
  234. let tokens = str.split(' ').filter(function (token) {
  235. return token !== '';
  236. });
  237.  
  238. let stack = [];
  239. for (let i = 0; i < tokens.length; i++) {
  240. let token = tokens[i];
  241. if (token in OPS) {
  242. stack.push(myNew(OPS[token].op,
  243. stack.splice(stack.length - OPS[token].opCount, OPS[token].opCount)));
  244. } else if (token in VARS) {
  245. stack.push(variableCreator.get(token));
  246. } else if (!isNaN(parseInt(token))) {
  247. stack.push(new Const(parseInt(token)));
  248. } else {
  249. // some problems happened
  250. }
  251. }
  252.  
  253. return stack.pop();
  254. };
  255.  
  256. let exceptions = function () {
  257. let exceptionFactory = function (msg) {
  258. let Exception = function (idx, token) {
  259. this.name = msg + " on position " + idx + ", where '" + token + "' is";
  260. };
  261. Exception.prototype = Error.prototype;
  262. return Exception;
  263. };
  264.  
  265. let ClosingParenthesisMissingException = exceptionFactory(
  266. 'Closing parenthesis expected'
  267. );
  268. let ExpressionEndExpectedException = exceptionFactory(
  269. 'End of expression expected'
  270. );
  271. var OperationExpectedException = exceptionFactory(
  272. 'Operation symbol expected'
  273. );
  274. var OperandExpectedException = exceptionFactory(
  275. 'Operand expected'
  276. );
  277. let EndOfConstantExpectedException = exceptionFactory(
  278. 'End of constant expected'
  279. );
  280. var InvalidOperandsAmountException = exceptionFactory(
  281. 'Invalid operands amount found'
  282. );
  283.  
  284. return {
  285. ClosingParenthesisMissingException: ClosingParenthesisMissingException,
  286. ExpressionEndExpectedException: ExpressionEndExpectedException,
  287. OperationExpectedException: OperationExpectedException,
  288. OperandExpectedException: OperandExpectedException,
  289. EndOfConstantExpectedException: EndOfConstantExpectedException,
  290. InvalidOperandsAmountException: InvalidOperandsAmountException,
  291. }
  292. }();
  293.  
  294. let Tokenizer = function (str) {
  295. this.idx = 0;
  296. this.oldToken = '';
  297. this.token = '';
  298.  
  299. var isWhitespace = function (c) {
  300. return /[\s]/.test("" + c);
  301. };
  302.  
  303. this.nextToken = function () {
  304. this.oldToken = this.token;
  305. while (this.idx < str.length && isWhitespace(str[this.idx])) {
  306. this.idx++;
  307. }
  308. this.token = '';
  309. if (str[this.idx] === '(' || str[this.idx] === ')') {
  310. this.token = str[this.idx++];
  311. } else {
  312. while (this.idx < str.length &&
  313. !isWhitespace(str[this.idx]) && str[this.idx] !== '(' && str[this.idx] !== ')') {
  314. this.token += str[this.idx++];
  315. }
  316. }
  317. };
  318. };
  319.  
  320. let parseOperand = function (tokenizer, parseExpression) {
  321. if (tokenizer.token === '(') {
  322. return parseExpression();
  323. } else if (tokenizer.token in VARS) {
  324. tokenizer.nextToken();
  325. return variableCreator.get(tokenizer.oldToken);
  326. } else if (tokenizer.token !== '' && !isNaN(tokenizer.token)) {
  327. tokenizer.nextToken();
  328. return new Const(parseInt(tokenizer.oldToken));
  329. } else {
  330. throw new exceptions.OperandExpectedException(tokenizer.idx, tokenizer.token);
  331. }
  332. };
  333.  
  334. let parsePrefix = function (str) {
  335. var tokenizer = new Tokenizer(str);
  336.  
  337. var parseExpression = function () {
  338. if (tokenizer.token === '(') {
  339. tokenizer.nextToken();
  340. if (!(tokenizer.token in OPS)) {
  341. throw new exceptions.OperationExpectedException(tokenizer.idx, tokenizer.token);
  342. }
  343. var op = OPS[tokenizer.token];
  344. tokenizer.nextToken();
  345. var args = [];
  346. for (var i = 0; i < op.opCount; i++) {
  347. args.push(parseOperand(tokenizer, parseExpression));
  348. }
  349. if (tokenizer.token !== ')') {
  350. throw new exceptions.ClosingParenthesisMissingException(tokenizer.idx, tokenizer.token);
  351. }
  352. tokenizer.nextToken();
  353. return myNew(op.op, args);
  354. } else {
  355. return parseOperand(tokenizer, parseExpression);
  356. }
  357. };
  358.  
  359. tokenizer.nextToken();
  360. var res = parseExpression();
  361. if (tokenizer.token !== '') {
  362. throw new exceptions.ExpressionEndExpectedException(tokenizer.idx, tokenizer.token);
  363. }
  364. return res;
  365. };
  366.  
  367. let parsePostfix = function (str) {
  368. let tokenizer = new Tokenizer(str);
  369.  
  370. var parseExpression = function () {
  371. if (tokenizer.token === '(') {
  372. tokenizer.nextToken();
  373. var args = [];
  374. while (!(tokenizer.token in OPS)) {
  375. args.push(parseOperand(tokenizer, parseExpression));
  376. }
  377. var op = OPS[tokenizer.token];
  378. if (args.length !== op.opCount) {
  379. throw new exceptions.InvalidOperandsAmountException(tokenizer.idx, tokenizer.token);
  380. }
  381. tokenizer.nextToken();
  382. if (tokenizer.token !== ')') {
  383. throw new exceptions.ClosingParenthesisMissingException(tokenizer.idx, tokenizer.token);
  384. }
  385. tokenizer.nextToken();
  386. return myNew(op.op, args);
  387. } else {
  388. return parseOperand(tokenizer, parseExpression);
  389. }
  390. };
  391.  
  392. tokenizer.nextToken();
  393. let res = parseExpression();
  394. if (tokenizer.token !== '') {
  395. throw new exceptions.ExpressionEndExpectedException(tokenizer.idx, tokenizer.token);
  396. }
  397. return res;
  398. };
  399.  
  400. return {
  401. Const: Const,
  402. Variable: Variable,
  403.  
  404. ArcTan: ArcTan,
  405. Exp: Exp,
  406. Negate: Negate,
  407. Square: Square,
  408. Sqrt: Sqrt,
  409.  
  410. Add: Add,
  411. Subtract: Subtract,
  412. Multiply: Multiply,
  413. Divide: Divide,
  414.  
  415. parse: parse,
  416. parsePrefix: parsePrefix,
  417. parsePostfix: parsePostfix,
  418. }
  419.  
  420. })();
  421.  
  422. let Const = expressions.Const,
  423. Variable = expressions.Variable,
  424.  
  425. ArcTan = expressions.ArcTan,
  426. Exp = expressions.Exp,
  427. Negate = expressions.Negate,
  428. Square = expressions.Square,
  429. Sqrt = expressions.Sqrt,
  430.  
  431. Add = expressions.Add,
  432. Subtract = expressions.Subtract,
  433. Multiply = expressions.Multiply,
  434. Divide = expressions.Divide,
  435.  
  436. parse = expressions.parse,
  437. parsePrefix = expressions.parsePrefix,
  438. parsePostfix = expressions.parsePostfix;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement