Browse Source

Implement let bindings

master
Dylan Baker 5 years ago
parent
commit
c93190c567
4 changed files with 41 additions and 4 deletions
  1. 1
    0
      src/ast.js
  2. 8
    4
      src/evaluator.js
  3. 25
    0
      src/parser.js
  4. 7
    0
      test/evaluatorTest.js

+ 1
- 0
src/ast.js View File

@@ -16,6 +16,7 @@ module.exports = {
16 16
   Definition: class Definition extends Node {},
17 17
   Identifier: class Identifier extends Node {},
18 18
   Lambda: class Lambda extends Node {},
19
+  LetBinding: class LetBinding extends Node {},
19 20
   List: class List extends Node {},
20 21
   Number: class Number extends Node {},
21 22
   String: class String extends Node {},

+ 8
- 4
src/evaluator.js View File

@@ -15,10 +15,6 @@ module.exports = class Evaluator {
15 15
       }
16 16
     })
17 17
 
18
-    console.log(
19
-      require('util').inspect(evaluatedTree, { depth: null })
20
-    )
21
-
22 18
     return evaluatedTree
23 19
   }
24 20
 
@@ -35,6 +31,14 @@ module.exports = class Evaluator {
35 31
       case AST.Definition:
36 32
         this.env.set(node.symbol.name, node.value)
37 33
         return false
34
+      case AST.LetBinding:
35
+        let innerEnv = new Env(env)
36
+
37
+        node.bindings.forEach(binding => {
38
+          innerEnv.set(binding.key.name, binding.value)
39
+        })
40
+
41
+        return this.evalNode(node.body, innerEnv)
38 42
       case AST.Conditional:
39 43
         let result = this.evalNode(node.condition, env)
40 44
 

+ 25
- 0
src/parser.js View File

@@ -57,6 +57,9 @@ module.exports = class Parser {
57 57
     } else if (this.tokenStream.peek().value === 'if') {
58 58
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
59 59
       node = this.conditional()
60
+    } else if (this.tokenStream.peek().value === 'let') {
61
+      this.tokenStream.eat(tokenTypes.IDENTIFIER)
62
+      node = this.let()
60 63
     } else {
61 64
       node = new AST.Application()
62 65
 
@@ -129,6 +132,28 @@ module.exports = class Parser {
129 132
     })
130 133
   }
131 134
 
135
+  let() {
136
+    let bindings = []
137
+
138
+    this.tokenStream.eat(tokenTypes.OPAREN)
139
+
140
+    while (this.tokenStream.peek().type !== tokenTypes.CPAREN) {
141
+      this.tokenStream.eat(tokenTypes.OPAREN)
142
+      bindings.push({
143
+        key: new AST.Identifier({
144
+          name: this.tokenStream.eat(tokenTypes.IDENTIFIER).value,
145
+        }),
146
+        value: this.expr(),
147
+      })
148
+      this.tokenStream.eat(tokenTypes.CPAREN)
149
+    }
150
+
151
+    this.tokenStream.eat(tokenTypes.CPAREN)
152
+
153
+    return new AST.LetBinding({
154
+      bindings: bindings,
155
+      body: this.expr(),
156
+    })
132 157
   }
133 158
 
134 159
   number() {

+ 7
- 0
test/evaluatorTest.js View File

@@ -40,3 +40,10 @@ test('conditionals', t => {
40 40
   tree = helpers.evaluate('(if (= (+ 4 9) (- 20 7)) (+ 10 9) (- 4 2))')
41 41
   t.deepEqual(tree[0], new AST.Number({ value: 19 }))
42 42
 })
43
+
44
+test('let bindings', t => {
45
+  t.plan(1)
46
+
47
+  const tree = helpers.evaluate('(let ((x 1) (y 2)) (+ x y))')
48
+  t.deepEqual(tree[0], new AST.Number({ value: 3 }))
49
+})

Loading…
Cancel
Save