daily pastebin goal
18%
SHARE
TWEET

blagoipidor.js

a guest Mar 24th, 2019 50 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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;
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top