m-chrzan.xyz
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-12 22:54:33 -0400
committerMarcin Chrzanowski <marcin.j.chrzanowski@gmail.com>2017-07-12 22:54:33 -0400
commit38e82ade6fd207af21f2df6a3e98298338e85eb8 (patch)
tree356dcc3a2ee6bcc43bf2bdad43c20fb72096d897
parent3915ca0932333f3d0d01538df915ac38810949cc (diff)
Lex basic dice
-rw-r--r--__tests__/lexer.test.js29
-rw-r--r--src/lexer.js44
2 files changed, 73 insertions, 0 deletions
diff --git a/__tests__/lexer.test.js b/__tests__/lexer.test.js
new file mode 100644
index 0000000..20d461f
--- /dev/null
+++ b/__tests__/lexer.test.js
@@ -0,0 +1,29 @@
+const { lex } = require('../src/lexer.js')
+
+describe('lex', () => {
+ it('lexes the empty string', () => {
+ expect(lex('')).toEqual([])
+ })
+
+ it('signals an error on unexpected input', () => {
+ expect(lex('q')).toBe('error')
+ })
+
+ describe('basic dice', () => {
+ it('1d6', () => {
+ expect(lex('1d6')).toEqual([
+ { type: 'number', value: 1 },
+ { type: 'd' },
+ { type: 'number', value: 6 }
+ ])
+ })
+
+ it('42d172', () => {
+ expect(lex('42d172')).toEqual([
+ { type: 'number', value: 42 },
+ { type: 'd' },
+ { type: 'number', value: 172 }
+ ])
+ })
+ })
+})
diff --git a/src/lexer.js b/src/lexer.js
new file mode 100644
index 0000000..ff7b0d4
--- /dev/null
+++ b/src/lexer.js
@@ -0,0 +1,44 @@
+const lexemeTypes = []
+
+const newLexemeType = (type, regex, adder) => {
+ lexemeTypes.push({
+ type,
+ regex: new RegExp(`^(${regex})(.*)$`),
+ adder: adder || (lexemes => { lexemes.push({ type }) })
+ })
+}
+
+const newValueLexeme = (type, regex, converter = v => v) => {
+ newLexemeType(type, regex, (lexemes, value) => {
+ lexemes.push({ type, value: converter(value) })
+ })
+}
+
+newValueLexeme('number', '\\d+', Number)
+newLexemeType('d', 'd')
+
+const lex = (expressionString) => {
+ let lexemes = []
+
+ while (expressionString.length > 0) {
+ let matched = false
+
+ lexemeTypes.forEach(lexemeType => {
+ let matches = lexemeType.regex.exec(expressionString)
+
+ if (matches) {
+ matched = true
+ lexemeType.adder(lexemes, matches[1])
+ expressionString = matches[2]
+ }
+ })
+
+ if (!matched) {
+ return 'error'
+ }
+ }
+
+ return lexemes
+}
+
+exports.lex = lex