Browse Source

Implement definitions

master
Dylan Baker 5 years ago
parent
commit
9662adf8aa
5 changed files with 43 additions and 6 deletions
  1. 7
    0
      src/ast/definition.js
  2. 2
    0
      src/ast/index.js
  3. 14
    4
      src/evaluator.js
  4. 10
    0
      src/parser.js
  5. 10
    2
      test/evaluatorTest.js

+ 7
- 0
src/ast/definition.js View File

@@ -0,0 +1,7 @@
1
+const Node = require('./node')
2
+
3
+module.exports = class Definition extends Node {
4
+  constructor(opts) {
5
+    super(opts)
6
+  }
7
+}

+ 2
- 0
src/ast/index.js View File

@@ -2,6 +2,7 @@ const Application = require("./application");
2 2
 const Attribute = require("./attribute");
3 3
 const Boolean = require("./boolean");
4 4
 const Conditional = require('./conditional')
5
+const Definition = require('./definition')
5 6
 const Identifier = require("./identifier");
6 7
 const Lambda = require("./lambda");
7 8
 const List = require("./list");
@@ -14,6 +15,7 @@ module.exports = {
14 15
   Attribute: Attribute,
15 16
   Boolean: Boolean,
16 17
   Conditional: Conditional,
18
+  Definition: Definition,
17 19
   Identifier: Identifier,
18 20
   Lambda: Lambda,
19 21
   List: List,

+ 14
- 4
src/evaluator.js View File

@@ -3,16 +3,24 @@ const Env = require('./env')
3 3
 
4 4
 module.exports = class Evaluator {
5 5
   eval(tree, env) {
6
+    this.env = env
7
+
6 8
     let evaluatedTree = []
7 9
 
8 10
     tree.forEach(node => {
9
-      evaluatedTree.push(this.evalNode(node, env))
11
+      let evaluatedNode = this.evalNode(node)
12
+
13
+      if (evaluatedNode) {
14
+        evaluatedTree.push(evaluatedNode)
15
+      }
10 16
     })
11 17
 
12 18
     return evaluatedTree
13 19
   }
14 20
 
15 21
   evalNode(node, env) {
22
+    if (!env) env = this.env
23
+
16 24
     switch (node.constructor) {
17 25
       case AST.Boolean:
18 26
       case AST.Number:
@@ -20,6 +28,9 @@ module.exports = class Evaluator {
20 28
         return node
21 29
       case AST.Identifier:
22 30
         return env.get(node.name)
31
+      case AST.Definition:
32
+        this.env.set(node.symbol.name, node.value)
33
+        return false
23 34
       case AST.Application:
24 35
         switch (node.function.constructor) {
25 36
           case AST.Identifier:
@@ -28,10 +39,9 @@ module.exports = class Evaluator {
28 39
                 function: env.get(node.function.name),
29 40
                 args: node.args,
30 41
               }),
31
-              env
32 42
             )
33 43
           case AST.Lambda:
34
-            let innerEnv = new Env()
44
+            let innerEnv = new Env(env)
35 45
 
36 46
             node.function.parameters.forEach((param, index) => {
37 47
               innerEnv.set(param.name, node.args[index])
@@ -40,7 +50,7 @@ module.exports = class Evaluator {
40 50
             return this.evalNode(node.function.body, innerEnv)
41 51
           case Function:
42 52
             let args = node.args.map(arg => {
43
-              return this.evalNode(arg, env)
53
+              return this.evalNode(arg)
44 54
             })
45 55
             args.unshift(this)
46 56
             return node.function.call(...args)

+ 10
- 0
src/parser.js View File

@@ -51,6 +51,9 @@ module.exports = class Parser {
51 51
     if (this.tokenStream.peek().value === 'lambda') {
52 52
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
53 53
       node = this.lambda()
54
+    } else if (this.tokenStream.peek().value === 'define') {
55
+      this.tokenStream.eat(tokenTypes.IDENTIFIER)
56
+      node = this.definition()
54 57
     } else if (this.tokenStream.peek().value === 'if') {
55 58
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
56 59
       node = this.conditional()
@@ -92,6 +95,13 @@ module.exports = class Parser {
92 95
     })
93 96
   }
94 97
 
98
+  definition() {
99
+    return new AST.Definition({
100
+      symbol: this.identifier(),
101
+      value: this.expr(),
102
+    })
103
+  }
104
+
95 105
   lambda() {
96 106
     let parameters = []
97 107
 

+ 10
- 2
test/evaluatorTest.js View File

@@ -8,7 +8,6 @@ test('applies functions from core library', t => {
8 8
   t.plan(1)
9 9
 
10 10
   const tree = helpers.evaluate('(+ 1 2)')
11
-
12 11
   t.deepEqual(tree[0], new AST.Number({ value: 3 }))
13 12
 })
14 13
 
@@ -16,6 +15,15 @@ test('applies lambda functions', t => {
16 15
   t.plan(1)
17 16
 
18 17
   const tree = helpers.evaluate('((lambda (x y) (+ x y)) 1 2)')
19
-
20 18
   t.deepEqual(tree[0], new AST.Number({ value: 3 }))
21 19
 })
20
+
21
+test('define', t => {
22
+  t.plan(2)
23
+
24
+  let tree = helpers.evaluate('(define x 5) (+ x 1)')
25
+  t.deepEqual(tree[0], new AST.Number({ value: 6 }))
26
+
27
+  tree = helpers.evaluate('(define plusOne (lambda (x) (+ x 1))) (plusOne 5)')
28
+  t.deepEqual(tree[0], new AST.Number({ value: 6 }))
29
+})

Loading…
Cancel
Save