Skip to content

Commit 236114c

Browse files
authored
Merge pull request #9 from airjp73/unary-operators
Unary operators
2 parents 56b07d7 + 1032996 commit 236114c

File tree

4 files changed

+57
-7
lines changed

4 files changed

+57
-7
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@airjp73/dice-notation",
3-
"version": "1.1.1",
3+
"version": "1.2.0",
44
"description": "A js library for parsing dice notation",
55
"module": "dist/module/index.js",
66
"main": "dist/main/index.js",

src/__test__/roll.test.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,31 @@ describe('roll', () => {
1010
['1d12 * 2d4 / 2', 1, 48, 200],
1111
['1d4 + 1d4 + 1d4 + 1d4', 4, 16, 24],
1212
['1d4 * (1d4 + 2)', 3, 24, 30],
13+
['1d2', 1, 2, 10],
1314

1415
// Constants to truly verify operator precedence
1516
['2 + 3 * (4 + 2)', 20, 20, 1],
17+
['2*2', 4, 4, 1],
1618
['4*4 + 4 / 2 -10', 8, 8, 1],
1719
['(2 + 2) * (3 * (3 - 1)) - (3 + 1)', 20, 20, 1],
18-
19-
// TODO: Support negatives?
2020
['64 * (0-3) - 4008 / 5 + (0-328)', -1321.6, -1321.6, 1],
21+
['2', 2, 2, 1],
22+
23+
// Support for unary operators
24+
['2 + -2', 0, 0, 1],
25+
['-2 + 2', 0, 0, 1],
26+
['+2 + 2', 4, 4, 1],
27+
['-2 + -2', -4, -4, 1],
28+
['2 * -2', -4, -4, 1],
29+
['-2 * -2', 4, 4, 1],
30+
['+2 / -2', -1, -1, 1],
31+
['------2', 2, 2, 1],
32+
['2 + ------2', 4, 4, 1],
33+
['++++++2 + ------2', 4, 4, 1],
34+
['-1d6 + -2d4', -14, -3, 20],
35+
['+1d6 + +2d4', 3, 14, 20],
36+
['+1d6 - +2d4', -7, 4, 20],
37+
['-(1d6 + -6) - +(4 + 5)', -9, -4, 20],
2138
];
2239

2340
it.each(cases)('should correctly roll %s', (notation, min, max, repeats) => {
@@ -27,6 +44,15 @@ describe('roll', () => {
2744
expect(result).toBeGreaterThanOrEqual(min);
2845
}
2946
});
47+
48+
const errorCases: [string, string][] = [
49+
['2 + *3', "Operator '*' may not be used as a unary operator"],
50+
['2 + /3', "Operator '/' may not be used as a unary operator"],
51+
];
52+
53+
it.each(errorCases)('should correctly error on %s', (notation, error) => {
54+
expect(() => roll(notation)).toThrowError(error);
55+
});
3056
});
3157

3258
describe('rollDice', () => {

src/calculateFinalResult.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ function doMath(val1: number, operator: Operator, val2: number): number {
1717
}
1818
}
1919

20+
function calculateUnaryOperation(operator: Operator, val: number): number {
21+
switch (operator) {
22+
case '*':
23+
case '/':
24+
throw new Error(
25+
`Operator '${operator}' may not be used as a unary operator`
26+
);
27+
case '+':
28+
return +val;
29+
case '-':
30+
return -val;
31+
}
32+
}
33+
2034
const isOperator = (stackItem: ValueOrOperatorString): stackItem is Operator =>
2135
typeof stackItem === 'string';
2236
const isValue = (stackItem: ValueOrOperatorString): stackItem is number =>
@@ -53,9 +67,19 @@ function calculateFinalResult(tokens: Token[], values: RollTotal[]): number {
5367
let total = popValue();
5468

5569
while (stack.length) {
56-
const operator = popOperator();
57-
const value = popValue();
58-
total = doMath(value, operator, total);
70+
let operator = popOperator();
71+
72+
while (isOperator(peekTop())) {
73+
total = calculateUnaryOperation(operator, total);
74+
operator = popOperator();
75+
}
76+
77+
if (isNil(peekTop())) {
78+
total = calculateUnaryOperation(operator, total);
79+
} else {
80+
const value = popValue();
81+
total = doMath(value, operator, total);
82+
}
5983
}
6084

6185
stack.push(total);

0 commit comments

Comments
 (0)