Browse Source

Use classes after all

master
Dylan Baker 6 years ago
parent
commit
fdee6a6367
4 changed files with 75 additions and 66 deletions
  1. 54
    64
      src/lexer.js
  2. 8
    0
      src/tokenStream.js
  3. 9
    0
      src/tokenTypes.js
  4. 4
    2
      test/lexer.js

+ 54
- 64
src/lexer.js View File

@@ -1,69 +1,59 @@
1
-const tokenTypes = {
2
-  OPAREN: '(',
3
-  CPAREN: ')',
4
-  KEYWORD: 'keyword',
5
-  QUOTE: '"',
6
-  LITERAL: 'literal',
7
-  ATTRIBUTE: 'attribute',
8
-  EOF: 'eof',
9
-}
1
+const TokenStream = require('./tokenStream')
2
+const tokenTypes = require('./tokenTypes')
10 3
 
11
-const scan = source => {
12
-  let pos = 0
13
-  let line = 1
14
-  let tokens = []
4
+module.exports = class Lexer {
5
+  scan(source) {
6
+    let pos = 0
7
+    let line = 1
8
+    let tokens = new TokenStream()
15 9
 
16
-  while (pos < source.length) {
17
-    if (source[pos].match(/\(/)) {
18
-      tokens.push({
19
-        type: tokenTypes.OPAREN,
20
-        line: line,
21
-      })
22
-      pos++
23
-    } else if (source[pos].match(/\)/)) {
24
-      tokens.push({
25
-        type: tokenTypes.CPAREN,
26
-        line: line,
27
-      })
28
-      pos++
29
-    } else if (source[pos].match(/['"]/)) {
30
-      tokens.push({
31
-        type: tokenTypes.QUOTE,
32
-        line: line,
33
-      })
34
-      pos++
35
-    } else if (source[pos].match(/:/)) {
36
-      let value = /:([^()'"\s]+)/.exec(source)[1].trim()
37
-      tokens.push({
38
-        type: tokenTypes.ATTRIBUTE,
39
-        line: line,
40
-        value: value,
41
-      })
42
-      pos += value.length + 1 // the +1 is to account for the colon
43
-    } else if (source[pos].match(/\n/)) {
44
-      line++
45
-      pos++
46
-    } else if (source[pos].match(/\s/)) {
47
-      pos++
48
-    } else {
49
-      let value = /[^()"':]+/.exec(source.slice(pos))[0]
50
-      tokens.push({
51
-        type: tokenTypes.LITERAL,
52
-        line: line,
53
-        value: value.trim(),
54
-      })
55
-      pos += value.length
10
+    while (pos < source.length) {
11
+      if (source[pos].match(/\(/)) {
12
+        tokens.push({
13
+          type: tokenTypes.OPAREN,
14
+          line: line,
15
+        })
16
+        pos++
17
+      } else if (source[pos].match(/\)/)) {
18
+        tokens.push({
19
+          type: tokenTypes.CPAREN,
20
+          line: line,
21
+        })
22
+        pos++
23
+      } else if (source[pos].match(/['"]/)) {
24
+        tokens.push({
25
+          type: tokenTypes.QUOTE,
26
+          line: line,
27
+        })
28
+        pos++
29
+      } else if (source[pos].match(/:/)) {
30
+        let value = /:([^()'"\s]+)/.exec(source)[1].trim()
31
+        tokens.push({
32
+          type: tokenTypes.ATTRIBUTE,
33
+          line: line,
34
+          value: value,
35
+        })
36
+        pos += value.length + 1 // the +1 is to account for the colon
37
+      } else if (source[pos].match(/\n/)) {
38
+        line++
39
+        pos++
40
+      } else if (source[pos].match(/\s/)) {
41
+        pos++
42
+      } else {
43
+        let value = /[^()"':]+/.exec(source.slice(pos))[0]
44
+        tokens.push({
45
+          type: tokenTypes.LITERAL,
46
+          line: line,
47
+          value: value.trim(),
48
+        })
49
+        pos += value.length
50
+      }
56 51
     }
57
-  }
58 52
 
59
-  tokens.push({
60
-    type: tokenTypes.EOF,
61
-    line: line,
62
-  })
63
-  return tokens
64
-}
65
-
66
-module.exports = {
67
-  scan: scan,
68
-  tokenTypes: tokenTypes,
53
+    tokens.push({
54
+      type: tokenTypes.EOF,
55
+      line: line,
56
+    })
57
+    return tokens
58
+  }
69 59
 }

+ 8
- 0
src/tokenStream.js View File

@@ -0,0 +1,8 @@
1
+module.exports = class TokenStream extends Array {
2
+  eat(tokenType) {
3
+    if (this[0] && this[0].type === tokenType) {
4
+      return this[0]
5
+    }
6
+    return false
7
+  }
8
+}

+ 9
- 0
src/tokenTypes.js View File

@@ -0,0 +1,9 @@
1
+module.exports = {
2
+  OPAREN: '(',
3
+  CPAREN: ')',
4
+  KEYWORD: 'keyword',
5
+  QUOTE: '"',
6
+  LITERAL: 'literal',
7
+  ATTRIBUTE: 'attribute',
8
+  EOF: 'eof',
9
+}

+ 4
- 2
test/lexer.js View File

@@ -1,10 +1,11 @@
1 1
 const test = require('tape')
2
-const lexer = require('../src/lexer')
3 2
 
4
-const tt = lexer.tokenTypes
3
+const Lexer = require('../src/lexer')
4
+const tt = require('../src/tokenTypes')
5 5
 
6 6
 test('lexes simple template correctly', t => {
7 7
   t.plan(4)
8
+  const lexer = new Lexer()
8 9
   let tokens = lexer.scan(
9 10
     '(div :class "foobar" (p "Lorem ipsum dolor sit amet"))',
10 11
   )
@@ -31,6 +32,7 @@ test('lexes simple template correctly', t => {
31 32
 
32 33
 test('keeps track of line numbers', t => {
33 34
   t.plan(2)
35
+  const lexer = new Lexer()
34 36
   let tokens = lexer.scan(`(
35 37
     (div :class "foobar"
36 38
       (p :class "bazquux"))

Loading…
Cancel
Save