Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- "use strict";
- let abstractOperation = {};
- abstractOperation.prototype = {
- evaluate : function() {
- const result = [];
- for (let f of this.operands) {
- result.push(f.evaluate(...arguments));
- }
- return this.operator(...result);
- },
- toString : function() {
- let toStr = "";
- for (let cur of this.operands) {
- toStr += cur.toString() + " ";
- }
- toStr += this.symbol;
- return toStr;
- },
- prefix : function() {
- let toStr = this.symbol;
- for (let cur of this.operands) {
- toStr += " " + cur.prefix();
- }
- return "(" + toStr + ")";
- }
- }
- let abstractAtomic = {};
- abstractAtomic.prototype = {
- toString : function() { return this.info + ""; },
- prefix : function() { return this.info + ""; },
- }
- const v = ["x", "y", "z"];
- function Atomic(evaluate) {
- function created(info) {
- this.info = (() => info)();
- }
- created.prototype = Object.create(abstractAtomic.prototype);
- created.prototype.evaluate = evaluate;
- return created;
- }
- const Variable = Atomic(function() {return arguments[v.indexOf(this.info)]});
- const Const = Atomic(function() { return this.info; });
- // :NOTE: you don't create operations of some specific prototype, you use prototype of global object
- // :NOTE: pass `arguments` each time is not well, get rid of that
- // :NOTE 2: in each instantiation of operator you override prototype of this operator
- // :NOTE 2: copy-paste code for operator declaration (at least call for `prototypeCreator`)
- function Opertion(sign, operator) {
- function created() {
- this.operands = (() => arguments)();
- }
- created.prototype = Object.create(abstractOperation.prototype);
- created.prototype.operator = (() => operator)();
- created.prototype.symbol = (() => sign)();
- return created;
- }
- const Add = Opertion("+", (a, b) => (a + b));
- const Subtract = Opertion("-", (a, b) => (a - b));
- const Multiply = Opertion("*", (a, b) => (a * b));
- const Divide = Opertion("/", (a, b) => (a / b));
- const Negate = Opertion("negate", a => -a);
- const Sinh = Opertion("sinh", a => Math.sinh(a));
- const Cosh = Opertion("cosh", a => Math.cosh(a));
- function ParseError(message) {
- this.message = message;
- }
- ParseError.prototype.constructor = ParseError;
- ParseError.prototype.name = "ParseError";
- function parsePrefix(expression) {
- let position = 0;
- let balance = 0;
- for (let i = 0; i < expression.length; i++) {
- if (expression.charAt(i) === '(') {
- balance++;
- }
- if (expression.charAt(i) === ')') {
- balance--;
- }
- if (balance < 0) {
- throw new ParseError("No open bracket for ) at position: " + position);
- }
- }
- function skipWS() {
- while (position < expression.length && expression.charAt(position) === ' ') {
- position++;
- }
- }
- function getNumber() {
- let start = position;
- while (position < expression.length && expression.charAt(position) >= '0' && expression.charAt(position) <= '9'
- || expression.charAt(position) === '-') {
- position++;
- }
- if (start == position) {
- return {};
- }
- return +expression.substring(start, position);
- }
- function getWord() {
- let start = position;
- while (position < expression.length && expression.charAt(position) != ' ' && expression.charAt(position) != '(') {
- position++;
- }
- return expression.substring(start, position);
- }
- function parseFunction() {
- switch(expression.charAt(position++)) {
- case '+':
- return {"f": Add, "arg" : 2};
- case '-':
- if(expression.charAt(position) != ' ' && expression.charAt(position) != '(') {
- position--;
- throw new ParseError("Expected operation, found: " + getWord());
- }
- return {"f": Subtract, "arg" : 2};
- case '*':
- return {"f": Multiply, "arg" : 2};
- case '/':
- return {"f": Divide, "arg" : 2};
- case 'n':
- let word_negate = getWord();
- if (word_negate === "egate") {
- return {"f": Negate, "arg" : 1};
- } else {
- throw new ParseError("Unknown operation: n" + word_negate);
- }
- case 's':
- let word_sinh = getWord();
- if (word_sinh === "inh") {
- return {"f": Sinh, "arg" : 2};
- } else {
- throw new ParseError("Unknown operation: s" + word_sinh);
- }
- case 'c':
- let word_cosh = getWord();
- if (word_cosh === "osh") {
- return {"f": Cosh, "arg" : 2};
- } else {
- throw new ParseError("Unknown operation: c" + word_cosh);
- }
- default :
- position--;
- throw new ParseError("Unknown operation: " + getWord());
- }
- }
- function parseExpression(inOperation) {
- let exp;
- let isOpened = false;
- skipWS();
- switch (expression.charAt(position)) {
- case '(':
- isOpened = true;
- position++;
- skipWS();
- let func = parseFunction();
- let args = [];
- for (let i = 0; i < func.arg; i++) {
- args[i] = parseExpression(true);
- }
- exp = new func.f(...args);
- skipWS();
- break;
- case 'x':
- case 'y':
- case 'z':
- exp = new Variable(expression.charAt(position++));
- if (!inOperation) {
- skipWS();
- if (position < expression.length - 1) {
- throw new ParseError("Incorrect \"argument\": " + getWord());
- }
- }
- break;
- default :
- let num = getNumber();
- if (!inOperation) {
- skipWS();
- if (position < expression.length - 1) {
- throw new PraseError("Incorrect \"argument\" " + getWord());
- }
- }
- if (isNaN(num)) {
- throw new ParseError("Incorrect \"argument\" " + getWord());
- } else {
- exp = new Const(+num);
- }
- break;
- }
- if (!isOpened) {
- if (position != expression.length && expression.charAt(position) != ' '
- && expression.charAt(position) != ')' && expression.charAt(position) != '(') {
- throw new ParseError("Incorrect expression, last symbol: " + expression.charAt(position));
- }
- } else {
- if (expression.charAt(position) != ')') {
- throw new ParseError("no )");
- }
- position++; // skip ")"
- }
- return exp;
- }
- return parseExpression(false);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement