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
   Definition: class Definition extends Node {},
16
   Definition: class Definition extends Node {},
17
   Identifier: class Identifier extends Node {},
17
   Identifier: class Identifier extends Node {},
18
   Lambda: class Lambda extends Node {},
18
   Lambda: class Lambda extends Node {},
19
+  LetBinding: class LetBinding extends Node {},
19
   List: class List extends Node {},
20
   List: class List extends Node {},
20
   Number: class Number extends Node {},
21
   Number: class Number extends Node {},
21
   String: class String extends Node {},
22
   String: class String extends Node {},

+ 8
- 4
src/evaluator.js View File

15
       }
15
       }
16
     })
16
     })
17
 
17
 
18
-    console.log(
19
-      require('util').inspect(evaluatedTree, { depth: null })
20
-    )
21
-
22
     return evaluatedTree
18
     return evaluatedTree
23
   }
19
   }
24
 
20
 
35
       case AST.Definition:
31
       case AST.Definition:
36
         this.env.set(node.symbol.name, node.value)
32
         this.env.set(node.symbol.name, node.value)
37
         return false
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
       case AST.Conditional:
42
       case AST.Conditional:
39
         let result = this.evalNode(node.condition, env)
43
         let result = this.evalNode(node.condition, env)
40
 
44
 

+ 25
- 0
src/parser.js View File

57
     } else if (this.tokenStream.peek().value === 'if') {
57
     } else if (this.tokenStream.peek().value === 'if') {
58
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
58
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
59
       node = this.conditional()
59
       node = this.conditional()
60
+    } else if (this.tokenStream.peek().value === 'let') {
61
+      this.tokenStream.eat(tokenTypes.IDENTIFIER)
62
+      node = this.let()
60
     } else {
63
     } else {
61
       node = new AST.Application()
64
       node = new AST.Application()
62
 
65
 
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
   number() {
159
   number() {

+ 7
- 0
test/evaluatorTest.js View File

40
   tree = helpers.evaluate('(if (= (+ 4 9) (- 20 7)) (+ 10 9) (- 4 2))')
40
   tree = helpers.evaluate('(if (= (+ 4 9) (- 20 7)) (+ 10 9) (- 4 2))')
41
   t.deepEqual(tree[0], new AST.Number({ value: 19 }))
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