Browse Source

Compile function applications (named and lambda)

master
Dylan Baker 5 years ago
parent
commit
06ab1b52d4
3 changed files with 78 additions and 1 deletions
  1. 26
    1
      src/compiler.js
  2. 26
    0
      src/env.js
  3. 26
    0
      test/compilerTest.js

+ 26
- 1
src/compiler.js View File

@@ -1,8 +1,15 @@
1 1
 const AST = require('./ast')
2
+const Env = require('./env')
2 3
 
3 4
 module.exports = class Compiler {
4
-  constructor() {
5
+  constructor(env = null) {
5 6
     this.result = ''
7
+
8
+    if (env) {
9
+      this.env = env
10
+    } else {
11
+      this.env = new Env()
12
+    }
6 13
   }
7 14
 
8 15
   compile(tree) {
@@ -18,6 +25,24 @@ module.exports = class Compiler {
18 25
       case AST.Number:
19 26
       case AST.String:
20 27
         return node.value
28
+      case AST.Identifier:
29
+        return this.compileNode(this.env.get(node.name))
30
+      case AST.Application:
31
+
32
+        if (node.function.constructor === AST.Identifier) {
33
+          let f = this.env.get(node.function.name)
34
+          return f(...node.args.map(arg => this.compileNode(arg)))
35
+        } else if (node.function.constructor === AST.FunctionDefinition) {
36
+          let env = new Env(this.env)
37
+          node.function.parameters.forEach((param, index) => {
38
+            env.set(param.name, node.args[index])
39
+          })
40
+
41
+          let compiler = new Compiler(env)
42
+          return compiler.compileNode(node.function.body)
43
+        }
44
+
45
+        return ''
21 46
     }
22 47
   }
23 48
 }

+ 26
- 0
src/env.js View File

@@ -0,0 +1,26 @@
1
+module.exports = class Env {
2
+  constructor(parent = null) {
3
+    if (parent) {
4
+      this.data = parent.data
5
+    } else {
6
+      this.data = {
7
+        '+': (a, b) => a + b,
8
+        '-': (a, b) => a - b,
9
+        '*': (a, b) => a * b,
10
+        '/': (a, b) => a / b,
11
+      }
12
+    }
13
+  }
14
+
15
+  get(symbol) {
16
+    if (this.data[symbol]) {
17
+      return this.data[symbol]
18
+    }
19
+
20
+    throw `Symbol ${symbol} is not bound`
21
+  }
22
+
23
+  set(symbol, value) {
24
+    this.data[symbol] = value
25
+  }
26
+}

+ 26
- 0
test/compilerTest.js View File

@@ -18,3 +18,29 @@ test('compiles strings', t => {
18 18
 
19 19
   t.equal(result, "hello world")
20 20
 })
21
+
22
+test('compiles core function applications', t => {
23
+  t.plan(4)
24
+
25
+  let result = helpers.compile('(+ 10 8)')
26
+  t.equal(result, '18')
27
+
28
+  result = helpers.compile('(- 7 3)')
29
+  t.equal(result, '4')
30
+
31
+  result = helpers.compile('(* 9 3)')
32
+  t.equal(result, '27')
33
+
34
+  result = helpers.compile('(/ 10 2)')
35
+  t.equal(result, '5')
36
+})
37
+
38
+test('compiles lambda expressions in the function position', t => {
39
+  t.plan(2)
40
+
41
+  let result = helpers.compile('((lambda (x) (+ x 1)) 2)')
42
+  t.equal(result, '3')
43
+
44
+  result = helpers.compile('((lambda (x y) (+ x y)) 2 3)')
45
+  t.equal(result, '5')
46
+})

Loading…
Cancel
Save