m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-15 22:48:10 -0400
committerMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-15 23:09:22 -0400
commite0ab43bcdc050ca3cac2adea927817d99700737e (patch)
treee11746830954eba9ec7a030f5588325c53a258ef
parent522654d5bf68636a39477f67fa4fd04961f5a6d0 (diff)
Throw Error on syntax errors
-rw-r--r--__tests__/lexer.test.js12
-rw-r--r--__tests__/parser.test.js17
-rw-r--r--src/lexer.js2
-rw-r--r--src/parser.js18
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
}