Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- let expressions = (function () {
- function myNew(constructor, args) {
- let instance = Object.create(constructor.prototype);
- constructor.apply(instance, args);
- return instance;
- }
- let VARS = {
- 'x': 0,
- 'y': 1,
- 'z': 2
- };
- let OPS = {};
- let Primitive = function () {
- this.prefix = function () {
- return '' + this.value;
- };
- this.postfix = function () {
- return '' + this.value;
- };
- this.toString = function () {
- return '' + this.value;
- };
- };
- let Const = function (value) {
- this.value = value;
- };
- Const.prototype = new Primitive();
- Const.prototype.evaluate = function () {
- return this.value;
- };
- Const.prototype.diff = function () {
- return Const.ZERO;
- };
- Const.ZERO = new Const(0);
- Const.ONE = new Const(1);
- Const.TWO = new Const(2);
- let Variable = function (name) {
- this.value = name;
- this.index = VARS[this.value];
- };
- Variable.prototype = new Primitive();
- Variable.prototype.evaluate = function () {
- return arguments[this.index];
- };
- Variable.prototype.diff = function (name) {
- return name === this.value ? Const.ONE : Const.ZERO;
- };
- let Creator = function () {
- this.requested = {};
- this.get = function (name) {
- if (!(name in this.requested)) {
- this.requested[name] = new Variable(name);
- }
- return this.requested[name];
- }
- };
- let variableCreator = new Creator();
- let AbstractOperator = function (symbol, operation, derivative) {
- this.op = function (index) {
- return this.operands[index];
- };
- this.prefix = function () {
- return '(' + symbol + ' ' + this.operands.map(function (elem) {
- return elem.prefix();
- }).join(' ') + ')';
- };
- this.postfix = function () {
- return '(' + this.operands.map(function (elem) {
- return elem.postfix()
- }).join(' ') + ' ' + symbol + ')';
- };
- this.toString = function () {
- return this.operands.join(' ') + ' ' + symbol;
- };
- this.evaluate = function () {
- let args = arguments;
- return operation(...this.operands.map(function (elem) {
- return elem.evaluate.apply(elem, args);
- }));
- };
- this.diff = function (name) {
- return derivative.call(this, name);
- };
- };
- let operatorFactory = function (symbol, operation, derivative) {
- let Operator = function () {
- this.operands = [].slice.call(arguments);
- };
- Operator.prototype = new AbstractOperator(symbol, operation, derivative);
- OPS[symbol] = {
- op: Operator,
- opCount: operation.length
- };
- return Operator;
- };
- let ArcTan = operatorFactory(
- 'atan',
- function (a) {
- return Math.atan(a);
- },
- function (name) {
- return new Multiply(
- new Divide(
- Const.ONE,
- new Add(
- new Multiply(this.op(0), this.op(0)),
- Const.ONE
- )
- ),
- this.op(0).diff(name)
- );
- }
- );
- let Exp = operatorFactory(
- 'exp',
- function (a) {
- return Math.exp(a);
- },
- function (name) {
- return new Multiply(
- this,
- this.op(0).diff(name)
- );
- }
- );
- let Negate = operatorFactory(
- 'negate',
- function (a) {
- return -a;
- },
- function (name) {
- return new Negate(this.op(0).diff(name));
- }
- );
- let Square = operatorFactory(
- 'square',
- function (a) {
- return a * a;
- },
- function (name) {
- return new Multiply(
- Const.TWO,
- new Multiply(this.op(0), this.op(0).diff(name))
- );
- }
- );
- let Sqrt = operatorFactory(
- 'sqrt',
- function (a) {
- return Math.pow(Math.abs(a), 0.5);
- },
- function (name) {
- return new Divide(
- new Multiply(this.op(0).diff(name), this.op(0)),
- new Multiply(
- Const.TWO,
- new Sqrt(new Multiply(
- this.op(0),
- new Multiply(this.op(0), this.op(0)))
- )
- )
- );
- }
- );
- let Add = operatorFactory(
- '+',
- function (a, b) {
- return a + b;
- },
- function (name) {
- return new Add(this.op(0).diff(name), this.op(1).diff(name));
- }
- );
- let Subtract = operatorFactory(
- '-',
- function (a, b) {
- return a - b;
- },
- function (name) {
- return new Subtract(this.op(0).diff(name), this.op(1).diff(name));
- }
- );
- let Multiply = operatorFactory(
- '*',
- function (a, b) {
- return a * b;
- },
- function (name) {
- return new Add(
- new Multiply(this.op(0), this.op(1).diff(name)),
- new Multiply(this.op(0).diff(name), this.op(1))
- );
- }
- );
- let Divide = operatorFactory(
- '/',
- function (a, b) {
- return a / b;
- },
- function (name) {
- return new Divide(
- new Subtract(
- new Multiply(this.op(0).diff(name), this.op(1)),
- new Multiply(this.op(0), this.op(1).diff(name))
- ),
- new Multiply(this.op(1), this.op(1))
- );
- }
- );
- let parse = function (str) {
- let tokens = str.split(' ').filter(function (token) {
- return token !== '';
- });
- let stack = [];
- for (let i = 0; i < tokens.length; i++) {
- let token = tokens[i];
- if (token in OPS) {
- stack.push(myNew(OPS[token].op,
- stack.splice(stack.length - OPS[token].opCount, OPS[token].opCount)));
- } else if (token in VARS) {
- stack.push(variableCreator.get(token));
- } else if (!isNaN(parseInt(token))) {
- stack.push(new Const(parseInt(token)));
- } else {
- // some problems happened
- }
- }
- return stack.pop();
- };
- let exceptions = function () {
- let exceptionFactory = function (msg) {
- let Exception = function (idx, token) {
- this.name = msg + " on position " + idx + ", where '" + token + "' is";
- };
- Exception.prototype = Error.prototype;
- return Exception;
- };
- let ClosingParenthesisMissingException = exceptionFactory(
- 'Closing parenthesis expected'
- );
- let ExpressionEndExpectedException = exceptionFactory(
- 'End of expression expected'
- );
- var OperationExpectedException = exceptionFactory(
- 'Operation symbol expected'
- );
- var OperandExpectedException = exceptionFactory(
- 'Operand expected'
- );
- let EndOfConstantExpectedException = exceptionFactory(
- 'End of constant expected'
- );
- var InvalidOperandsAmountException = exceptionFactory(
- 'Invalid operands amount found'
- );
- return {
- ClosingParenthesisMissingException: ClosingParenthesisMissingException,
- ExpressionEndExpectedException: ExpressionEndExpectedException,
- OperationExpectedException: OperationExpectedException,
- OperandExpectedException: OperandExpectedException,
- EndOfConstantExpectedException: EndOfConstantExpectedException,
- InvalidOperandsAmountException: InvalidOperandsAmountException,
- }
- }();
- let Tokenizer = function (str) {
- this.idx = 0;
- this.oldToken = '';
- this.token = '';
- var isWhitespace = function (c) {
- return /[\s]/.test("" + c);
- };
- this.nextToken = function () {
- this.oldToken = this.token;
- while (this.idx < str.length && isWhitespace(str[this.idx])) {
- this.idx++;
- }
- this.token = '';
- if (str[this.idx] === '(' || str[this.idx] === ')') {
- this.token = str[this.idx++];
- } else {
- while (this.idx < str.length &&
- !isWhitespace(str[this.idx]) && str[this.idx] !== '(' && str[this.idx] !== ')') {
- this.token += str[this.idx++];
- }
- }
- };
- };
- let parseOperand = function (tokenizer, parseExpression) {
- if (tokenizer.token === '(') {
- return parseExpression();
- } else if (tokenizer.token in VARS) {
- tokenizer.nextToken();
- return variableCreator.get(tokenizer.oldToken);
- } else if (tokenizer.token !== '' && !isNaN(tokenizer.token)) {
- tokenizer.nextToken();
- return new Const(parseInt(tokenizer.oldToken));
- } else {
- throw new exceptions.OperandExpectedException(tokenizer.idx, tokenizer.token);
- }
- };
- let parsePrefix = function (str) {
- var tokenizer = new Tokenizer(str);
- var parseExpression = function () {
- if (tokenizer.token === '(') {
- tokenizer.nextToken();
- if (!(tokenizer.token in OPS)) {
- throw new exceptions.OperationExpectedException(tokenizer.idx, tokenizer.token);
- }
- var op = OPS[tokenizer.token];
- tokenizer.nextToken();
- var args = [];
- for (var i = 0; i < op.opCount; i++) {
- args.push(parseOperand(tokenizer, parseExpression));
- }
- if (tokenizer.token !== ')') {
- throw new exceptions.ClosingParenthesisMissingException(tokenizer.idx, tokenizer.token);
- }
- tokenizer.nextToken();
- return myNew(op.op, args);
- } else {
- return parseOperand(tokenizer, parseExpression);
- }
- };
- tokenizer.nextToken();
- var res = parseExpression();
- if (tokenizer.token !== '') {
- throw new exceptions.ExpressionEndExpectedException(tokenizer.idx, tokenizer.token);
- }
- return res;
- };
- let parsePostfix = function (str) {
- let tokenizer = new Tokenizer(str);
- var parseExpression = function () {
- if (tokenizer.token === '(') {
- tokenizer.nextToken();
- var args = [];
- while (!(tokenizer.token in OPS)) {
- args.push(parseOperand(tokenizer, parseExpression));
- }
- var op = OPS[tokenizer.token];
- if (args.length !== op.opCount) {
- throw new exceptions.InvalidOperandsAmountException(tokenizer.idx, tokenizer.token);
- }
- tokenizer.nextToken();
- if (tokenizer.token !== ')') {
- throw new exceptions.ClosingParenthesisMissingException(tokenizer.idx, tokenizer.token);
- }
- tokenizer.nextToken();
- return myNew(op.op, args);
- } else {
- return parseOperand(tokenizer, parseExpression);
- }
- };
- tokenizer.nextToken();
- let res = parseExpression();
- if (tokenizer.token !== '') {
- throw new exceptions.ExpressionEndExpectedException(tokenizer.idx, tokenizer.token);
- }
- return res;
- };
- return {
- Const: Const,
- Variable: Variable,
- ArcTan: ArcTan,
- Exp: Exp,
- Negate: Negate,
- Square: Square,
- Sqrt: Sqrt,
- Add: Add,
- Subtract: Subtract,
- Multiply: Multiply,
- Divide: Divide,
- parse: parse,
- parsePrefix: parsePrefix,
- parsePostfix: parsePostfix,
- }
- })();
- let Const = expressions.Const,
- Variable = expressions.Variable,
- ArcTan = expressions.ArcTan,
- Exp = expressions.Exp,
- Negate = expressions.Negate,
- Square = expressions.Square,
- Sqrt = expressions.Sqrt,
- Add = expressions.Add,
- Subtract = expressions.Subtract,
- Multiply = expressions.Multiply,
- Divide = expressions.Divide,
- parse = expressions.parse,
- parsePrefix = expressions.parsePrefix,
- parsePostfix = expressions.parsePostfix;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement