From d1aebf80bb490f1f6261726dc8bb4d986750b3ad Mon Sep 17 00:00:00 2001 From: Mohit Jain Date: Fri, 1 Sep 2023 15:45:06 +0530 Subject: [PATCH] Added JSDOC for challenge 7 - Write Your Own Calculator --- src/7/README.md | 10 +++++++++ src/7/calculator.ts | 25 ++++++++++++++++++++++ src/7/postfix.ts | 51 +++++++++++++++++++++++++++++++++++++++++++-- src/7/tokens.ts | 30 +++++++++++++++++++++++++- 4 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/7/README.md b/src/7/README.md index a945ef1..c8bd7bb 100644 --- a/src/7/README.md +++ b/src/7/README.md @@ -31,6 +31,16 @@ const str = '1 + 1'; const value = new Calculator(str).calculate(); // value = 2 ``` +You can also use the command line tool as follows: + +```bash +# Using node +node /path/to/calculator.index.js '1 + 1' + +# Using ts-node +npx ts-node calculator.index.ts '1 + 1' +``` + ## Run tests To run the tests for the Calculator tool, go to the root directory of this repository and run the following command: diff --git a/src/7/calculator.ts b/src/7/calculator.ts index d6e2285..b59e212 100644 --- a/src/7/calculator.ts +++ b/src/7/calculator.ts @@ -3,8 +3,28 @@ import { Postfix } from './postfix'; import { OperatorTokens } from './tokens'; export class Calculator { + /** + * The input provided by the user + * + * @type {string} + */ text: string; + + /** + * The Postfix class instance + * + * @private + * @type {Postfix} + */ private postfix: Postfix; + + /** + * Stack used after infix to postfix conversion. + * Used for calculating the value of the expression. + * + * @private + * @type {Stack} + */ private stack: Stack; constructor(text: string) { @@ -14,11 +34,14 @@ export class Calculator { } public calculate(): number { + // First convert the infix notation to postfix notation. const queue = this.postfix.parse(); while (queue.size() > 0) { + // Get the next token from the queue. const str = queue.dequeue()!; + // If the token is an operator, pop two values from the stack, if (OperatorTokens.has(str)) { const operator = str; @@ -47,8 +70,10 @@ export class Calculator { throw new Error(`Invalid operator ${str}`); } + // Perform the operation and push the result to the stack. this.stack.push(value); } else { + // If the token is an operand, push it to the stack. this.stack.push(parseFloat(str)); } } diff --git a/src/7/postfix.ts b/src/7/postfix.ts index 4cada39..f13553a 100644 --- a/src/7/postfix.ts +++ b/src/7/postfix.ts @@ -3,13 +3,55 @@ import { Stack } from '../utils/stack'; import { OperatorTokens } from './tokens'; export class Postfix { + /** + * Input infix string + * + * @private + * @type {string} + */ private text: string; + + /** + * Position of the current token + * + * @private + * @type {number} + */ private pos: number = 0; + + /** + * Final output queue + * + * @private + * @type {Queue} + */ private outputQueue: Queue; + + /** + * Data structure to store the operators + * + * @private + * @type {Stack} + */ private operatorStack: Stack; private textLength: number; - private operatorCount = 0; - private numberCount = 0; + + /** + * Number of operators encountered till `this.pos` + * + * @private + * @type {number} + */ + private operatorCount: number = 0; + + /** + * Number of operands encountered till `this.pos` + * @date 9/1/2023 - 1:44:00 PM + * + * @private + * @type {number} + */ + private numberCount: number = 0; constructor(text: string) { this.text = text; @@ -81,6 +123,7 @@ export class Postfix { private parseRightParenthesis() { this.consumeToken(); + // Pop all operators from the stack until we encounter a left parenthesis. while (this.operatorStack.peek() !== '(') { if (this.operatorStack.size() === 0) { throw new Error('Mismatched Parenthesis'); @@ -101,6 +144,7 @@ export class Postfix { this.consumeToken(); const token1 = OperatorTokens.get(o1)!; + // While there is an operator token, o2, at the top of the stack while (this.operatorStack.size() > 0) { const o2 = this.operatorStack.peek()!; @@ -108,6 +152,7 @@ export class Postfix { break; } + // If o1 is left-associative and its precedence is less than or equal to that of o2, const token2 = OperatorTokens.get(o2)!; if ( token2.precedence > token1.precedence || @@ -126,6 +171,7 @@ export class Postfix { private parseNumber(): string { this.numberCount++; let str = ''; + while (this.pos < this.textLength) { const token = this.getCurrentToken(); if (token === ' ' || token === ')') { @@ -134,6 +180,7 @@ export class Postfix { str += token; this.consumeToken(); } + return str; } diff --git a/src/7/tokens.ts b/src/7/tokens.ts index 4df5a0c..6faa38c 100644 --- a/src/7/tokens.ts +++ b/src/7/tokens.ts @@ -1,6 +1,29 @@ +/** + * Interface used for comparing operators. + * Used while converting infix to postfix notation. + * + * @interface IToken + */ interface IToken { + /** + * The operator character + * + * @type {string} + */ char: string; + + /** + * Precedence of the operator + * + * @type {number} + */ precedence: number; + + /** + * Whether the operator is left associative or not + * + * @type {boolean} + */ isLeftAssociative: boolean; } @@ -15,7 +38,12 @@ class Token implements IToken { } } -const OperatorTokens = new Map(); +/** + * All the operators supported by the calculator. + * + * @type {Map} + */ +const OperatorTokens: Map = new Map(); OperatorTokens.set('^', new Token('^', 4, false)); OperatorTokens.set('*', new Token('*', 3, true));