Browse Source

Implement conditionals

Currently I'm relying on JavaScript's semantics
around truthiness. I think I'm going to retain
that ease of use (i.e. `(if list #t #f)` should
return true if the list has more than 0 elements,
etc) but I want to specify that behavior myself.
master
Dylan Baker 5 years ago
parent
commit
76c6eac9b5
5 changed files with 52 additions and 1 deletions
  1. 7
    0
      src/ast/conditional.js
  2. 2
    0
      src/ast/index.js
  3. 8
    0
      src/compiler.js
  4. 12
    1
      src/parser.js
  5. 23
    0
      test/parserTest.js

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

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

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

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

+ 8
- 0
src/compiler.js View File

@@ -27,6 +27,14 @@ module.exports = class Compiler {
27 27
         return node.value
28 28
       case AST.Identifier:
29 29
         return this.compileNode(this.env.get(node.name))
30
+      case AST.Conditional:
31
+        let condition = this.compileNode(node.condition)
32
+
33
+        if (condition) {
34
+          return this.compileNode(node.ifCase)
35
+        } else {
36
+          return this.compileNode(node.elseCase)
37
+        }
30 38
       case AST.Application:
31 39
         if (node.function.constructor === AST.Identifier) {
32 40
           let f = this.env.get(node.function.name)

+ 12
- 1
src/parser.js View File

@@ -53,7 +53,10 @@ module.exports = class Parser {
53 53
 
54 54
     if (this.tokenStream.peek().value === 'lambda') {
55 55
       this.tokenStream.eat(tokenTypes.IDENTIFIER)
56
-      node = this.lambda(true)
56
+      node = this.lambda()
57
+    } else if (this.tokenStream.peek().value === 'if') {
58
+      this.tokenStream.eat(tokenTypes.IDENTIFIER)
59
+      node = this.conditional()
57 60
     } else {
58 61
       node = new AST.Application()
59 62
 
@@ -84,6 +87,14 @@ module.exports = class Parser {
84 87
     })
85 88
   }
86 89
 
90
+  conditional() {
91
+    return new AST.Conditional({
92
+      condition: this.expr(),
93
+      ifCase: this.expr(),
94
+      elseCase: this.expr(),
95
+    })
96
+  }
97
+
87 98
   lambda() {
88 99
     let parameters = []
89 100
 

+ 23
- 0
test/parserTest.js View File

@@ -72,3 +72,26 @@ test('parse lambdas and expressions in function position', t => {
72 72
     }),
73 73
   ])
74 74
 })
75
+
76
+test('parse conditionals', t => {
77
+  t.plan(1)
78
+  const tree = helpers.parse('(if #t (do this) (do that))')
79
+
80
+  t.deepEqual(tree, [
81
+    new AST.Conditional({
82
+      condition: new AST.Boolean({ value: true }),
83
+      ifCase: new AST.Application({
84
+        function: new AST.Identifier({ name: 'do' }),
85
+        args: [
86
+          new AST.Identifier({ name: 'this' })
87
+        ]
88
+      }),
89
+      elseCase: new AST.Application({
90
+        function: new AST.Identifier({ name: 'do' }),
91
+        args: [
92
+          new AST.Identifier({ name: 'that' })
93
+        ]
94
+      }),
95
+    })
96
+  ])
97
+})

Loading…
Cancel
Save