diff options
author | Marcin Chrzanowski <marcin.j.chrzanowski@gmail.com> | 2017-07-15 22:48:10 -0400 |
---|---|---|
committer | Marcin Chrzanowski <marcin.j.chrzanowski@gmail.com> | 2017-07-15 23:09:22 -0400 |
commit | e0ab43bcdc050ca3cac2adea927817d99700737e (patch) | |
tree | e11746830954eba9ec7a030f5588325c53a258ef | |
parent | 522654d5bf68636a39477f67fa4fd04961f5a6d0 (diff) |
Throw Error on syntax errors
-rw-r--r-- | __tests__/lexer.test.js | 12 | ||||
-rw-r--r-- | __tests__/parser.test.js | 17 | ||||
-rw-r--r-- | src/lexer.js | 2 | ||||
-rw-r--r-- | src/parser.js | 18 |
4 files changed, 43 insertions, 6 deletions
diff --git a/__tests__/lexer.test.js b/__tests__/lexer.test.js index 38c880e..b9260b8 100644 --- a/__tests__/lexer.test.js +++ b/__tests__/lexer.test.js @@ -5,8 +5,16 @@ describe('lex', () => { expect(lex('')).toEqual([]) }) - it('signals an error on unexpected input', () => { - expect(lex('q')).toBe('error') + it('throws on unexpected input', () => { + expect(() => { lex('q') }).toThrow(/Syntax error/) + }) + + it('throws on unexpected input at the end', () => { + expect(() => { lex('1d6 `') }).toThrow(/Syntax error/) + }) + + it('throws on unexpected input in the middle', () => { + expect(() => { lex('2d3 + b 3d4') }).toThrow(/Syntax error/) }) describe('ignores whitespace', () => { diff --git a/__tests__/parser.test.js b/__tests__/parser.test.js index 74ca442..f3c6e97 100644 --- a/__tests__/parser.test.js +++ b/__tests__/parser.test.js @@ -1,6 +1,23 @@ const { parse } = require('../src/parser.js') describe('parse', () => { + describe('error handling', () => { + it('throws when a binary operation lacks an argument', () => { + expect(() => { parse('1d') }).toThrow(/Syntax error/) + expect(() => { parse('2+3+') }).toThrow(/Syntax error/) + }) + + it('throws when two binary operations follow each other', () => { + expect(() => { parse('1dd2') }).toThrow(/Syntax error/) + expect(() => { parse('1+d2') }).toThrow(/Syntax error/) + }) + + it('throws when two dice not combined with a binary operation', () => { + expect(() => { parse('(1d4)(1d6)') }).toThrow(/Syntax error/) + expect(() => { parse('1 2') }).toThrow(/Syntax error/) + }) + }) + it('parses a constant', () => { expect(parse('5')).toEqual({ type: 'constant', value: 5 }) }) diff --git a/src/lexer.js b/src/lexer.js index f559816..5e29e42 100644 --- a/src/lexer.js +++ b/src/lexer.js @@ -43,7 +43,7 @@ const lex = (expressionString) => { }) if (!matched) { - return 'error' + throw new Error('Syntax error: unrecognized token') } } diff --git a/src/parser.js b/src/parser.js index 5b9b718..fc9add3 100644 --- a/src/parser.js +++ b/src/parser.js @@ -2,8 +2,17 @@ const { lex } = require('./lexer.js') let symbols = {} +let throwSyntaxError = () => { + throw new Error('Syntax error: unexpected token') +} + let newSymbol = (type, nud, lbp, led) => { - symbols[type] = { type, nud, lbp, led } + symbols[type] = { + type, + nud: nud || throwSyntaxError, + lbp, + led: led || throwSyntaxError + } } let lexemeToToken = lexeme => { @@ -65,7 +74,7 @@ const newParser = (tokens) => { if (this.token().type === token) { this.advanceToken() } else { - throw 'error' + throw throwSyntaxError() } }, expression: function(rbp) { @@ -89,7 +98,10 @@ const parse = expressionString => { tokens.push(symbols.end) const parser = newParser(tokens) - return parser.expression(0) + const expression = parser.expression(0) + parser.match('end') + + return expression } |