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

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
 const Attribute = require("./attribute");
2
 const Attribute = require("./attribute");
3
 const Boolean = require("./boolean");
3
 const Boolean = require("./boolean");
4
 const Conditional = require('./conditional')
4
 const Conditional = require('./conditional')
5
+const Definition = require('./definition')
5
 const Identifier = require("./identifier");
6
 const Identifier = require("./identifier");
6
 const Lambda = require("./lambda");
7
 const Lambda = require("./lambda");
7
 const List = require("./list");
8
 const List = require("./list");
14
   Attribute: Attribute,
15
   Attribute: Attribute,
15
   Boolean: Boolean,
16
   Boolean: Boolean,
16
   Conditional: Conditional,
17
   Conditional: Conditional,
18
+  Definition: Definition,
17
   Identifier: Identifier,
19
   Identifier: Identifier,
18
   Lambda: Lambda,
20
   Lambda: Lambda,
19
   List: List,
21
   List: List,

+ 14
- 4
src/evaluator.js View File

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

+ 10
- 0
src/parser.js View File

51
     if (this.tokenStream.peek().value === 'lambda') {
51
     if (this.tokenStream.peek().value === 'lambda') {
52
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
52
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
53
       node = this.lambda()
53
       node = this.lambda()
54
+    } else if (this.tokenStream.peek().value === 'define') {
55
+      this.tokenStream.eat(tokenTypes.IDENTIFIER)
56
+      node = this.definition()
54
     } else if (this.tokenStream.peek().value === 'if') {
57
     } else if (this.tokenStream.peek().value === 'if') {
55
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
58
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
56
       node = this.conditional()
59
       node = this.conditional()
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
   lambda() {
105
   lambda() {
96
     let parameters = []
106
     let parameters = []
97
 
107
 

+ 10
- 2
test/evaluatorTest.js View File

8
   t.plan(1)
8
   t.plan(1)
9
 
9
 
10
   const tree = helpers.evaluate('(+ 1 2)')
10
   const tree = helpers.evaluate('(+ 1 2)')
11
-
12
   t.deepEqual(tree[0], new AST.Number({ value: 3 }))
11
   t.deepEqual(tree[0], new AST.Number({ value: 3 }))
13
 })
12
 })
14
 
13
 
16
   t.plan(1)
15
   t.plan(1)
17
 
16
 
18
   const tree = helpers.evaluate('((lambda (x y) (+ x y)) 1 2)')
17
   const tree = helpers.evaluate('((lambda (x y) (+ x y)) 1 2)')
19
-
20
   t.deepEqual(tree[0], new AST.Number({ value: 3 }))
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