@flomsstaar/expression-tree 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +83 -0
  2. package/build/example.d.ts +1 -0
  3. package/build/example.js +18 -0
  4. package/build/index.d.ts +16 -0
  5. package/build/index.js +16 -0
  6. package/build/src/enums/binary_node_operator.d.ts +7 -0
  7. package/build/src/enums/binary_node_operator.js +8 -0
  8. package/build/src/enums/node_type.d.ts +6 -0
  9. package/build/src/enums/node_type.js +7 -0
  10. package/build/src/enums/unary_node_operator.d.ts +5 -0
  11. package/build/src/enums/unary_node_operator.js +6 -0
  12. package/build/src/errors/division_by_zero_error.d.ts +3 -0
  13. package/build/src/errors/division_by_zero_error.js +6 -0
  14. package/build/src/errors/invalid_expression_error.d.ts +3 -0
  15. package/build/src/errors/invalid_expression_error.js +6 -0
  16. package/build/src/errors/invalid_number_error.d.ts +4 -0
  17. package/build/src/errors/invalid_number_error.js +8 -0
  18. package/build/src/errors/invalid_square_root_error.d.ts +3 -0
  19. package/build/src/errors/invalid_square_root_error.js +6 -0
  20. package/build/src/errors/missing_parenthese_error.d.ts +3 -0
  21. package/build/src/errors/missing_parenthese_error.js +6 -0
  22. package/build/src/errors/unknown_binary_operator_error.d.ts +3 -0
  23. package/build/src/errors/unknown_binary_operator_error.js +6 -0
  24. package/build/src/errors/unknown_node_type_error.d.ts +3 -0
  25. package/build/src/errors/unknown_node_type_error.js +6 -0
  26. package/build/src/errors/unknown_unary_operator_error.d.ts +3 -0
  27. package/build/src/errors/unknown_unary_operator_error.js +6 -0
  28. package/build/src/expression_cutter.d.ts +4 -0
  29. package/build/src/expression_cutter.js +7 -0
  30. package/build/src/expression_evaluator.d.ts +10 -0
  31. package/build/src/expression_evaluator.js +74 -0
  32. package/build/src/expression_parser.d.ts +14 -0
  33. package/build/src/expression_parser.js +94 -0
  34. package/build/src/expression_tree.d.ts +10 -0
  35. package/build/src/expression_tree.js +18 -0
  36. package/build/src/index.d.ts +1 -0
  37. package/build/src/index.js +1 -0
  38. package/build/src/models/base_node.d.ts +5 -0
  39. package/build/src/models/base_node.js +6 -0
  40. package/build/src/models/binary_node.d.ts +8 -0
  41. package/build/src/models/binary_node.js +13 -0
  42. package/build/src/models/number_node.d.ts +6 -0
  43. package/build/src/models/number_node.js +12 -0
  44. package/build/src/models/unary_node.d.ts +7 -0
  45. package/build/src/models/unary_node.js +11 -0
  46. package/build/src/render_expression.d.ts +2 -0
  47. package/build/src/render_expression.js +56 -0
  48. package/build/tests/expression_cutter.test.d.ts +1 -0
  49. package/build/tests/expression_cutter.test.js +9 -0
  50. package/build/tests/expression_evaluator.test.d.ts +1 -0
  51. package/build/tests/expression_evaluator.test.js +110 -0
  52. package/build/tests/expression_parser.test.d.ts +1 -0
  53. package/build/tests/expression_parser.test.js +44 -0
  54. package/build/tests/expression_tree.test.d.ts +1 -0
  55. package/build/tests/expression_tree.test.js +12 -0
  56. package/build/tests/inputs/expression_cutter_input.d.ts +1 -0
  57. package/build/tests/inputs/expression_cutter_input.js +230 -0
  58. package/build/tests/inputs/expression_parser_input.d.ts +2 -0
  59. package/build/tests/inputs/expression_parser_input.js +197 -0
  60. package/build/tests/inputs/expression_tree_input.d.ts +1 -0
  61. package/build/tests/inputs/expression_tree_input.js +44 -0
  62. package/build/tests/number_node.test.d.ts +1 -0
  63. package/build/tests/number_node.test.js +16 -0
  64. package/build/tests/render_expression.test.d.ts +1 -0
  65. package/build/tests/render_expression.test.js +85 -0
  66. package/build/vitest.config.d.ts +2 -0
  67. package/build/vitest.config.js +10 -0
  68. package/package.json +47 -0
  69. package/src/enums/binary_node_operator.ts +7 -0
  70. package/src/enums/node_type.ts +6 -0
  71. package/src/enums/unary_node_operator.ts +5 -0
  72. package/src/errors/division_by_zero_error.ts +6 -0
  73. package/src/errors/invalid_expression_error.ts +6 -0
  74. package/src/errors/invalid_number_error.ts +6 -0
  75. package/src/errors/invalid_square_root_error.ts +6 -0
  76. package/src/errors/missing_parenthese_error.ts +6 -0
  77. package/src/errors/unknown_binary_operator_error.ts +6 -0
  78. package/src/errors/unknown_node_type_error.ts +6 -0
  79. package/src/errors/unknown_unary_operator_error.ts +6 -0
  80. package/src/expression_cutter.ts +9 -0
  81. package/src/expression_evaluator.ts +76 -0
  82. package/src/expression_parser.ts +117 -0
  83. package/src/expression_tree.ts +19 -0
  84. package/src/models/base_node.ts +5 -0
  85. package/src/models/binary_node.ts +13 -0
  86. package/src/models/number_node.ts +12 -0
  87. package/src/models/unary_node.ts +12 -0
  88. package/src/render_expression.ts +57 -0
@@ -0,0 +1,197 @@
1
+ import { BinaryNodeOperator } from '../../src/enums/binary_node_operator.js';
2
+ import { BinaryNode } from '../../src/models/binary_node.js';
3
+ import { NumberNode } from '../../src/models/number_node.js';
4
+ import { UnaryNodeOperator } from '../../src/enums/unary_node_operator.js';
5
+ import { UnaryNode } from '../../src/models/unary_node.js';
6
+ export function expressionParserInput() {
7
+ return [
8
+ // Classic cases
9
+ [['6', '+', '5'], new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(6), new NumberNode(5))],
10
+ [
11
+ ['6', '-', '5'],
12
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(6), new NumberNode(5)),
13
+ ],
14
+ [
15
+ ['6', '*', '5'],
16
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(6), new NumberNode(5)),
17
+ ],
18
+ [
19
+ ['6', '/', '5'],
20
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(6), new NumberNode(5)),
21
+ ],
22
+ [
23
+ ['6', '^', '5'],
24
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(6), new NumberNode(5)),
25
+ ],
26
+ [
27
+ ['64', '+', '5'],
28
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(64), new NumberNode(5)),
29
+ ],
30
+ [
31
+ ['64', '-', '5'],
32
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(64), new NumberNode(5)),
33
+ ],
34
+ [
35
+ ['64', '*', '5'],
36
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(64), new NumberNode(5)),
37
+ ],
38
+ [
39
+ ['64', '/', '5'],
40
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(64), new NumberNode(5)),
41
+ ],
42
+ [
43
+ ['64', '^', '5'],
44
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(64), new NumberNode(5)),
45
+ ],
46
+ [
47
+ ['6', '+', '25'],
48
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(6), new NumberNode(25)),
49
+ ],
50
+ [
51
+ ['6', '-', '25'],
52
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(6), new NumberNode(25)),
53
+ ],
54
+ [
55
+ ['6', '*', '25'],
56
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(6), new NumberNode(25)),
57
+ ],
58
+ [
59
+ ['6', '/', '25'],
60
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(6), new NumberNode(25)),
61
+ ],
62
+ [
63
+ ['6', '^', '25'],
64
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(6), new NumberNode(25)),
65
+ ],
66
+ [
67
+ ['12', '+', '34'],
68
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(12), new NumberNode(34)),
69
+ ],
70
+ [
71
+ ['12', '-', '34'],
72
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(12), new NumberNode(34)),
73
+ ],
74
+ [
75
+ ['12', '*', '34'],
76
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(12), new NumberNode(34)),
77
+ ],
78
+ [
79
+ ['12', '/', '34'],
80
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(12), new NumberNode(34)),
81
+ ],
82
+ [
83
+ ['12', '^', '34'],
84
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(12), new NumberNode(34)),
85
+ ],
86
+ // Parentheses
87
+ [
88
+ ['(', '6', '+', '5', ')'],
89
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(6), new NumberNode(5)),
90
+ ],
91
+ [
92
+ ['(', '6', '-', '5', ')'],
93
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(6), new NumberNode(5)),
94
+ ],
95
+ [
96
+ ['(', '6', '*', '5', ')'],
97
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(6), new NumberNode(5)),
98
+ ],
99
+ [
100
+ ['(', '6', '/', '5', ')'],
101
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(6), new NumberNode(5)),
102
+ ],
103
+ [
104
+ ['(', '6', '^', '5', ')'],
105
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(6), new NumberNode(5)),
106
+ ],
107
+ [
108
+ ['(', '64', '+', '5', ')'],
109
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(64), new NumberNode(5)),
110
+ ],
111
+ [
112
+ ['(', '64', '-', '5', ')'],
113
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(64), new NumberNode(5)),
114
+ ],
115
+ [
116
+ ['(', '64', '*', '5', ')'],
117
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(64), new NumberNode(5)),
118
+ ],
119
+ [
120
+ ['(', '64', '/', '5', ')'],
121
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(64), new NumberNode(5)),
122
+ ],
123
+ [
124
+ ['(', '64', '^', '5', ')'],
125
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(64), new NumberNode(5)),
126
+ ],
127
+ [
128
+ ['(', '6', '+', '25', ')'],
129
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(6), new NumberNode(25)),
130
+ ],
131
+ [
132
+ ['(', '6', '-', '25', ')'],
133
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(6), new NumberNode(25)),
134
+ ],
135
+ [
136
+ ['(', '6', '*', '25', ')'],
137
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(6), new NumberNode(25)),
138
+ ],
139
+ [
140
+ ['(', '6', '/', '25', ')'],
141
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(6), new NumberNode(25)),
142
+ ],
143
+ [
144
+ ['(', '6', '^', '25', ')'],
145
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(6), new NumberNode(25)),
146
+ ],
147
+ [
148
+ ['(', '12', '+', '34', ')'],
149
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(12), new NumberNode(34)),
150
+ ],
151
+ [
152
+ ['(', '12', '-', '34', ')'],
153
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(12), new NumberNode(34)),
154
+ ],
155
+ [
156
+ ['(', '12', '*', '34', ')'],
157
+ new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(12), new NumberNode(34)),
158
+ ],
159
+ [
160
+ ['(', '12', '/', '34', ')'],
161
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(12), new NumberNode(34)),
162
+ ],
163
+ [
164
+ ['(', '12', '^', '34', ')'],
165
+ new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(12), new NumberNode(34)),
166
+ ],
167
+ // Negative numbers
168
+ [
169
+ ['-', '6', '+', '5'],
170
+ new BinaryNode(BinaryNodeOperator.SUM, new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(6)), new NumberNode(5)),
171
+ ],
172
+ [
173
+ ['6', '+', '-', '5'],
174
+ new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(6), new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(5))),
175
+ ],
176
+ [
177
+ ['6', '-', '-', '5'],
178
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(6), new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(5))),
179
+ ],
180
+ [
181
+ ['-', '6', '-', '5'],
182
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(6)), new NumberNode(5)),
183
+ ],
184
+ [
185
+ ['-', '6', '-', '-', '5'],
186
+ new BinaryNode(BinaryNodeOperator.SUBTRACT, new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(6)), new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(5))),
187
+ ],
188
+ [
189
+ ['-', '(', '5', '+', '2', ')'],
190
+ new UnaryNode(UnaryNodeOperator.NEGATE, new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(5), new NumberNode(2))),
191
+ ],
192
+ [
193
+ ['-', '(', '5', '*', '2', '-', '4', ')', '/', '2'],
194
+ new BinaryNode(BinaryNodeOperator.DIVIDE, new UnaryNode(UnaryNodeOperator.NEGATE, new BinaryNode(BinaryNodeOperator.SUBTRACT, new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(5), new NumberNode(2)), new NumberNode(4))), new NumberNode(2)),
195
+ ],
196
+ ];
197
+ }
@@ -0,0 +1 @@
1
+ export declare function expressionTreeInput(): [string, number][];
@@ -0,0 +1,44 @@
1
+ export function expressionTreeInput() {
2
+ return [
3
+ ['6 + 5', 11],
4
+ ['6 - 5', 1],
5
+ ['6 * 5', 30],
6
+ ['6 / 5', 1.2],
7
+ ['6 ^ 5', 7776],
8
+ ['64 + 5', 69],
9
+ ['64 - 5', 59],
10
+ ['64 * 5', 320],
11
+ ['64 / 5', 12.8],
12
+ ['64 ^ 5', 1073741824],
13
+ ['6 + 25', 31],
14
+ ['6 - 25', -19],
15
+ ['6 * 25', 150],
16
+ ['6 / 25', 0.24],
17
+ ['6 ^ 12', 2176782336],
18
+ ['(6 ^ 2)', 36],
19
+ ['(2 ^ 15)', 32768],
20
+ ['(12 ^ 4)', 20736],
21
+ ['(6 + 5) ^ (4 * 3)', 3138428376721],
22
+ ['2 ^ -1', 0.5],
23
+ ['(6 + 5) * (3 - 1)', 22],
24
+ ['(6 + -2) * (3 - 1)', 8],
25
+ ['(6 + -2) * (3 - -1)', 16],
26
+ ['(6 + -2) * (3 - -1) / (3 + -1)', 8],
27
+ ['(6 + -2) * (3 - -1) / (3 + -1) / (2 + -1)', 8],
28
+ ['6 - -2 + 5', 13],
29
+ ['6 + -(2 + 5)', -1],
30
+ ['6 + -2 * 5', -4],
31
+ ['6 + -2 * (5 + 3)', -10],
32
+ ['6 + -2 * (5 + 3) / 2', -2],
33
+ ['6 + -2 * (5 + 3) / (3 + 1)', 2],
34
+ ['6 + -(2 * 5)', -4],
35
+ ['6 + 2 * 3 - 1', 11],
36
+ ['6 + 2 * (3 - 1)', 10],
37
+ ['6 + 2 * (3 - 1) / 2', 8],
38
+ ['6 + 2 * (3 - 1) / (3 + 1)', 7],
39
+ ['(6 + 2) * (3 - 1)', 16],
40
+ ['(6 + 2) * (4 - 1) / (2 + 1)', 8],
41
+ ['(6 + -2) * (3 - 1)', 8],
42
+ ['(6 + -2) * (3 - 2) / 2', 2],
43
+ ];
44
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { NumberNode } from '../src/models/number_node.js';
3
+ import { NodeType } from '../src/enums/node_type.js';
4
+ describe('number node', () => {
5
+ it('should create a number node with the correct value', () => {
6
+ const value = 42;
7
+ const node = new NumberNode(value);
8
+ expect(node.value).toBe(value);
9
+ expect(node.type).toBe(NodeType.NUMBER);
10
+ });
11
+ it('should return the correct string representation', () => {
12
+ const value = 42;
13
+ const node = new NumberNode(value);
14
+ expect(node.toString()).toBe(value.toString());
15
+ });
16
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,85 @@
1
+ import { describe, expect, it, test } from 'vitest';
2
+ import { UnaryNode } from '../src/models/unary_node.js';
3
+ import { UnaryNodeOperator } from '../src/enums/unary_node_operator.js';
4
+ import { NumberNode } from '../src/models/number_node.js';
5
+ import { renderExpression } from '../src/render_expression.js';
6
+ import { BinaryNode } from '../src/models/binary_node.js';
7
+ import { BinaryNodeOperator } from '../src/enums/binary_node_operator.js';
8
+ import { UnknownBinaryOperatorError } from '../src/errors/unknown_binary_operator_error.js';
9
+ import { UnknownNodeTypeError } from '../src/errors/unknown_node_type_error.js';
10
+ import { UnknownUnaryOperatorError } from '../src/errors/unknown_unary_operator_error.js';
11
+ describe('render expression', () => {
12
+ describe('unary node operations', () => {
13
+ describe('negation operation', () => {
14
+ it('should render a negation of a number', () => {
15
+ const expression = new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(5));
16
+ const result = renderExpression(expression);
17
+ expect(result).toBe('-5');
18
+ });
19
+ it('should render a negation of zero', () => {
20
+ const expression = new UnaryNode(UnaryNodeOperator.NEGATE, new NumberNode(0));
21
+ const result = renderExpression(expression);
22
+ expect(result).toBe('0');
23
+ });
24
+ it('should render a negation of an operation', () => {
25
+ const expression = new UnaryNode(UnaryNodeOperator.NEGATE, new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(3), new NumberNode(2)));
26
+ const result = renderExpression(expression);
27
+ expect(result).toBe('-(3 + 2)');
28
+ });
29
+ });
30
+ it('should render a square root of a number', () => {
31
+ const expression = new UnaryNode(UnaryNodeOperator.SQUARE_ROOT, new NumberNode(16));
32
+ const result = renderExpression(expression);
33
+ expect(result).toBe('sqrt(16)');
34
+ });
35
+ it('should render an absolute value of a number', () => {
36
+ const expression = new UnaryNode(UnaryNodeOperator.ABSOLUTE, new NumberNode(-10));
37
+ const result = renderExpression(expression);
38
+ expect(result).toBe('abs(-10)');
39
+ });
40
+ });
41
+ describe('binary node operations', () => {
42
+ it('should render a sum of two numbers', () => {
43
+ const expression = new BinaryNode(BinaryNodeOperator.SUM, new NumberNode(3), new NumberNode(2));
44
+ const result = renderExpression(expression);
45
+ expect(result).toBe('3 + 2');
46
+ });
47
+ it('should render a subtraction of two numbers', () => {
48
+ const expression = new BinaryNode(BinaryNodeOperator.SUBTRACT, new NumberNode(5), new NumberNode(2));
49
+ const result = renderExpression(expression);
50
+ expect(result).toBe('5 - 2');
51
+ });
52
+ it('should render a multiplication of two numbers', () => {
53
+ const expression = new BinaryNode(BinaryNodeOperator.MULTIPLY, new NumberNode(4), new NumberNode(3));
54
+ const result = renderExpression(expression);
55
+ expect(result).toBe('4 * 3');
56
+ });
57
+ it('should render a division of two numbers', () => {
58
+ const expression = new BinaryNode(BinaryNodeOperator.DIVIDE, new NumberNode(8), new NumberNode(2));
59
+ const result = renderExpression(expression);
60
+ expect(result).toBe('8 / 2');
61
+ });
62
+ it('should render a power operation', () => {
63
+ const expression = new BinaryNode(BinaryNodeOperator.POWER, new NumberNode(2), new NumberNode(3));
64
+ const result = renderExpression(expression);
65
+ expect(result).toBe('2 ^ 3');
66
+ });
67
+ });
68
+ describe('unsupported operations', () => {
69
+ test('unknown unary operator', () => {
70
+ const expression = new UnaryNode('UNKNOWN_UNARY_OPERATOR', new NumberNode(1));
71
+ expect(() => renderExpression(expression)).toThrowError(UnknownUnaryOperatorError);
72
+ });
73
+ test('unknown binary operator', () => {
74
+ const expression = new BinaryNode('UNKNOWN_OPERATOR', new NumberNode(1), new NumberNode(2));
75
+ expect(() => renderExpression(expression)).toThrowError(UnknownBinaryOperatorError);
76
+ });
77
+ test('unknown node type', () => {
78
+ const expression = {
79
+ type: 'UNKNOWN_NODE_TYPE',
80
+ value: 42,
81
+ };
82
+ expect(() => renderExpression(expression)).toThrowError(UnknownNodeTypeError);
83
+ });
84
+ });
85
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("vite").UserConfig;
2
+ export default _default;
@@ -0,0 +1,10 @@
1
+ import { defineConfig } from 'vitest/config';
2
+ export default defineConfig({
3
+ test: {
4
+ include: ['tests/**/*.test.ts'],
5
+ coverage: {
6
+ include: ['src/**/*.ts'],
7
+ reporter: ['text', 'lcov'],
8
+ },
9
+ },
10
+ });
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@flomsstaar/expression-tree",
3
+ "version": "0.1.0",
4
+ "main": "build/index.js",
5
+ "type": "module",
6
+ "files": [
7
+ "src",
8
+ "build"
9
+ ],
10
+ "exports": {
11
+ ".": "./build/index.js"
12
+ },
13
+ "scripts": {
14
+ "dev": "bun index.ts",
15
+ "lint": "eslint src index.ts",
16
+ "lint:fix": "eslint src index.ts --fix",
17
+ "format": "prettier --check src index.ts",
18
+ "format:fix": "prettier --write src index.ts",
19
+ "test": "vitest",
20
+ "coverage": "vitest run --coverage",
21
+ "typecheck": "bun run tsc --noEmit"
22
+ },
23
+ "devDependencies": {
24
+ "@adonisjs/eslint-config": "^2.1.0",
25
+ "@adonisjs/prettier-config": "^1.4.5",
26
+ "@adonisjs/tsconfig": "^1.4.1",
27
+ "@types/bun": "latest",
28
+ "@vitest/coverage-v8": "3.2.4",
29
+ "eslint": "^9.29.0",
30
+ "prettier": "^3.6.0",
31
+ "vitest": "^3.2.4"
32
+ },
33
+ "peerDependencies": {
34
+ "typescript": "^5.8.3"
35
+ },
36
+ "author": "Florent Marques <florent.marques19@gmail.com>",
37
+ "license": "MIT",
38
+ "keywords": [
39
+ "expression-tree",
40
+ "calculator"
41
+ ],
42
+ "repository": "https://github.com/flomSStaar/expression-tree-ts",
43
+ "eslintConfig": {
44
+ "extends": "@adonisjs/eslint-config/app"
45
+ },
46
+ "prettier": "@adonisjs/prettier-config"
47
+ }
@@ -0,0 +1,7 @@
1
+ export enum BinaryNodeOperator {
2
+ SUM = 'addition',
3
+ SUBTRACT = 'subtraction',
4
+ MULTIPLY = 'multiplication',
5
+ DIVIDE = 'division',
6
+ POWER = 'power',
7
+ }
@@ -0,0 +1,6 @@
1
+ export enum NodeType {
2
+ EXPRESSION = 'expression',
3
+ NUMBER = 'number',
4
+ BINARY = 'binary',
5
+ UNARY = 'unary',
6
+ }
@@ -0,0 +1,5 @@
1
+ export enum UnaryNodeOperator {
2
+ SQUARE_ROOT = 'square_root',
3
+ NEGATE = 'negate',
4
+ ABSOLUTE = 'absolute',
5
+ }
@@ -0,0 +1,6 @@
1
+ export class DivisionByZeroError extends Error {
2
+ constructor() {
3
+ super('Division by zero is not allowed')
4
+ this.name = 'DivisionByZeroError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class InvalidExpressionError extends Error {
2
+ constructor() {
3
+ super('Invalid expression encountered during parsing')
4
+ this.name = 'InvalidExpressionError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class InvalidNumberError extends Error {
2
+ constructor(public readonly token: string | null = null) {
3
+ super('Invalid number format')
4
+ this.name = 'InvalidNumberError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class NegativeSquareRootError extends Error {
2
+ constructor() {
3
+ super('Cannot take square root of a negative number')
4
+ this.name = 'InvalidSquareRootError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class MissingClosingParenthesisError extends Error {
2
+ constructor() {
3
+ super('Missing closing parenthesis in the expression')
4
+ this.name = 'MissingClosingParenthesisError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class UnknownBinaryOperatorError extends Error {
2
+ constructor(operator: string) {
3
+ super(`Unknown binary operator: ${operator}`)
4
+ this.name = 'UnknownBinaryOperatorError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class UnknownNodeTypeError extends Error {
2
+ constructor(nodeType: string) {
3
+ super(`Unknown node type: ${nodeType}`)
4
+ this.name = 'UnknownNodeTypeError'
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ export class UnknownUnaryOperatorError extends Error {
2
+ constructor(operator: string) {
3
+ super(`Unknown unary operator: ${operator}`)
4
+ this.name = 'UnknownUnaryOperatorError'
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ export class ExpressionCutter {
2
+ static readonly REGEX = /(\d+(?:\.\d+)?|\+|-|\*|\^|\/|\(|\)|sqrt|abs)/g
3
+
4
+ cut(expression: string): string[] {
5
+ const cleanExpr = expression.replace(/\s+/g, '')
6
+
7
+ return Array.from(cleanExpr.matchAll(ExpressionCutter.REGEX)).map((m) => m[0])
8
+ }
9
+ }
@@ -0,0 +1,76 @@
1
+ import { BinaryNode } from './models/binary_node.js'
2
+ import type { BaseNode } from './models/base_node.js'
3
+ import { UnaryNode } from './models/unary_node.js'
4
+ import { NumberNode } from './models/number_node.js'
5
+ import { UnknownNodeTypeError } from './errors/unknown_node_type_error.js'
6
+ import { BinaryNodeOperator } from './enums/binary_node_operator.js'
7
+ import { UnaryNodeOperator } from './enums/unary_node_operator.js'
8
+ import { NegativeSquareRootError } from './errors/invalid_square_root_error.js'
9
+ import { UnknownUnaryOperatorError } from './errors/unknown_unary_operator_error.js'
10
+ import { UnknownBinaryOperatorError } from './errors/unknown_binary_operator_error.js'
11
+ import { DivisionByZeroError } from './errors/division_by_zero_error.js'
12
+
13
+ export class ExpressionEvaluator {
14
+ public evaluate(node: BaseNode): number {
15
+ if (node instanceof BinaryNode) {
16
+ return this.evaluateBinaryNode(node)
17
+ } else if (node instanceof UnaryNode) {
18
+ return this.evaluateUnaryNode(node)
19
+ } else if (node instanceof NumberNode) {
20
+ return this.evaluateNumberNode(node)
21
+ } else {
22
+ throw new UnknownNodeTypeError(node.type)
23
+ }
24
+ }
25
+
26
+ protected evaluateBinaryNode(node: BinaryNode): number {
27
+ switch (node.operator) {
28
+ case BinaryNodeOperator.SUM: {
29
+ return this.evaluate(node.left) + this.evaluate(node.right)
30
+ }
31
+ case BinaryNodeOperator.SUBTRACT: {
32
+ return this.evaluate(node.left) - this.evaluate(node.right)
33
+ }
34
+ case BinaryNodeOperator.MULTIPLY: {
35
+ return this.evaluate(node.left) * this.evaluate(node.right)
36
+ }
37
+ case BinaryNodeOperator.DIVIDE: {
38
+ const leftValue = this.evaluate(node.left)
39
+ const rightValue = this.evaluate(node.right)
40
+ if (rightValue === 0) {
41
+ throw new DivisionByZeroError()
42
+ }
43
+ return leftValue / rightValue
44
+ }
45
+ case BinaryNodeOperator.POWER: {
46
+ return Math.pow(this.evaluate(node.left), this.evaluate(node.right))
47
+ }
48
+ default:
49
+ throw new UnknownBinaryOperatorError(node.operator)
50
+ }
51
+ }
52
+
53
+ protected evaluateUnaryNode(node: UnaryNode): number {
54
+ switch (node.operator) {
55
+ case UnaryNodeOperator.NEGATE: {
56
+ return -this.evaluate(node.value)
57
+ }
58
+ case UnaryNodeOperator.ABSOLUTE: {
59
+ return Math.abs(this.evaluate(node.value))
60
+ }
61
+ case UnaryNodeOperator.SQUARE_ROOT: {
62
+ const leftValue = this.evaluate(node.value)
63
+ if (leftValue < 0) {
64
+ throw new NegativeSquareRootError()
65
+ }
66
+ return Math.sqrt(leftValue)
67
+ }
68
+ default:
69
+ throw new UnknownUnaryOperatorError(node.operator)
70
+ }
71
+ }
72
+
73
+ protected evaluateNumberNode(node: NumberNode): number {
74
+ return node.value
75
+ }
76
+ }