Browse Source

Replace Application with List

I see what I was going for with the Application AST node but
Chervil is a Lisp after all and lists are the fundamental data
structure. The direct reason I wanted to do this was for quoted values,
since a quoted list isn't an application.
master
Dylan Baker 5 years ago
parent
commit
26a93cd9f0

+ 1
- 1
lib/chervil/ast.rb View File

@@ -2,12 +2,12 @@ require "chervil"
2 2
 
3 3
 module Chervil
4 4
   module AST
5
-    require "chervil/ast/application"
6 5
     require "chervil/ast/boolean"
7 6
     require "chervil/ast/conditional"
8 7
     require "chervil/ast/definition"
9 8
     require "chervil/ast/function"
10 9
     require "chervil/ast/identifier"
10
+    require "chervil/ast/list"
11 11
     require "chervil/ast/number"
12 12
     require "chervil/ast/string"
13 13
   end

+ 0
- 27
lib/chervil/ast/application.rb View File

@@ -1,27 +0,0 @@
1
-module Chervil::AST
2
-  class Application
3
-    attr_reader :expr
4
-    attr_reader :arguments
5
-
6
-    def initialize(expr, arguments)
7
-      @expr = expr
8
-      @arguments = arguments
9
-    end
10
-
11
-    def ==(other)
12
-      @expr == other.expr && @arguments == other.arguments
13
-    end
14
-
15
-    def evaluate(env)
16
-      if @expr.class == Identifier
17
-        function = env.get(@expr.name)
18
-
19
-        if function.nil?
20
-          ::Chervil::Error.new("Unbound variable #{@expr.name}")
21
-        else
22
-          function.call(@arguments.map { |arg| arg.evaluate(env) }, env)
23
-        end
24
-      end
25
-    end
26
-  end
27
-end

+ 30
- 0
lib/chervil/ast/list.rb View File

@@ -0,0 +1,30 @@
1
+module Chervil::AST
2
+  class List
3
+    attr_reader :elements
4
+
5
+    def initialize(elements)
6
+      @elements = elements
7
+    end
8
+
9
+    def ==(other)
10
+      @elements == other.elements
11
+    end
12
+
13
+    def evaluate(env)
14
+      if elements.empty?
15
+        []
16
+      else
17
+        head = @elements.first
18
+        if head.class == Identifier
19
+          function = env.get(head.name)
20
+
21
+          if function.nil?
22
+            ::Chervil::Error.new("Unbound variable #{head.name}")
23
+          else
24
+            function.call(@elements[1..-1].map { |arg| arg.evaluate(env) }, env)
25
+          end
26
+        end
27
+      end
28
+    end
29
+  end
30
+end

+ 5
- 7
lib/chervil/parser.rb View File

@@ -21,13 +21,13 @@ module Chervil
21 21
       elsif @current_token.type == :identifier
22 22
         identifier
23 23
       elsif @current_token.type == :lparen
24
-        application
24
+        list
25 25
       else
26 26
         @error = Error.new("Unexpected token #{@current_token.type}: #{@current_token.value}")
27 27
       end
28 28
     end
29 29
 
30
-    def application
30
+    def list
31 31
       eat(:lparen)
32 32
 
33 33
       if @current_token.type == :identifier
@@ -38,16 +38,14 @@ module Chervil
38 38
         end
39 39
       end
40 40
 
41
-      expression = expr
42
-
43
-      args = Array.new
41
+      elements = Array.new
44 42
       until @current_token.type == :rparen || @current_token.type == :eof
45
-        args << expr
43
+        elements << expr
46 44
       end
47 45
 
48 46
       eat(:rparen)
49 47
 
50
-      AST::Application.new(expression, args)
48
+      AST::List.new(elements)
51 49
     end
52 50
 
53 51
     def definition

+ 0
- 41
spec/ast/application_spec.rb View File

@@ -1,41 +0,0 @@
1
-module Chervil
2
-  RSpec.describe AST::Application do
3
-    it 'evaluates addition' do
4
-      env = Env.new
5
-      expect(
6
-        AST::Application.new(
7
-          AST::Identifier.new('+'),
8
-          [AST::Number.new(1.0), AST::Number.new(2.0)]
9
-        )
10
-          .evaluate(env)
11
-      ).to eq(3.0)
12
-    end
13
-
14
-    it 'evaluates nested arithmetic' do
15
-      env = Env.new
16
-      expect(
17
-        AST::Application.new(
18
-          AST::Identifier.new('+'),
19
-          [
20
-            AST::Application.new(
21
-              AST::Identifier.new('+'),
22
-              [AST::Number.new(1.0), AST::Number.new(2.0)]
23
-            ),
24
-            AST::Application.new(
25
-              AST::Identifier.new('+'),
26
-              [AST::Number.new(3.0), AST::Number.new(4.0)]
27
-            )
28
-          ]
29
-        )
30
-          .evaluate(env)
31
-      ).to eq(10.0)
32
-    end
33
-
34
-    it 'returns an error if the function is not defined' do
35
-      env = Env.new
36
-      expect(AST::Application.new(AST::Identifier.new("x"), []).evaluate(env)).to eq(
37
-        Error.new("Unbound variable x")
38
-      )
39
-    end
40
-  end
41
-end

+ 4
- 4
spec/ast/conditional_spec.rb View File

@@ -22,9 +22,9 @@ module Chervil
22 22
 
23 23
     it 'evaluates complex predicates' do
24 24
       expect(AST::Conditional.new(
25
-        AST::Application.new(
26
-          AST::Identifier.new(">"),
25
+        AST::List.new(
27 26
           [
27
+            AST::Identifier.new(">"),
28 28
             AST::Number.new(2.0),
29 29
             AST::Number.new(1.0),
30 30
           ]
@@ -39,9 +39,9 @@ module Chervil
39 39
     it 'evaluates complex branches' do
40 40
       expect(AST::Conditional.new(
41 41
         AST::Boolean.new(true),
42
-        AST::Application.new(
43
-          AST::Identifier.new("+"),
42
+        AST::List.new(
44 43
           [
44
+            AST::Identifier.new("+"),
45 45
             AST::Number.new(2.0),
46 46
             AST::Number.new(1.0),
47 47
           ]

+ 2
- 2
spec/ast/function_spec.rb View File

@@ -8,9 +8,9 @@ module Chervil
8 8
             AST::Identifier.new("x")
9 9
           ],
10 10
           [
11
-            AST::Application.new(
12
-              AST::Identifier.new("*"),
11
+            AST::List.new(
13 12
               [
13
+                AST::Identifier.new("*"),
14 14
                 AST::Identifier.new("x"),
15 15
                 AST::Identifier.new("x")
16 16
               ]

+ 47
- 0
spec/ast/list_spec.rb View File

@@ -0,0 +1,47 @@
1
+module Chervil
2
+  RSpec.describe AST::List do
3
+    it 'evaluates addition' do
4
+      env = Env.new
5
+      expect(
6
+        AST::List.new(
7
+          [AST::Identifier.new('+'),
8
+          AST::Number.new(1.0), AST::Number.new(2.0)]
9
+        )
10
+          .evaluate(env)
11
+      ).to eq(3.0)
12
+    end
13
+
14
+    it 'evaluates nested arithmetic' do
15
+      env = Env.new
16
+      expect(
17
+        AST::List.new(
18
+          [
19
+            AST::Identifier.new('+'),
20
+            AST::List.new(
21
+              [
22
+                AST::Identifier.new('+'),
23
+                AST::Number.new(1.0),
24
+                AST::Number.new(2.0)
25
+              ]
26
+            ),
27
+            AST::List.new(
28
+              [
29
+                AST::Identifier.new('+'),
30
+                AST::Number.new(3.0),
31
+                AST::Number.new(4.0)
32
+              ]
33
+            )
34
+          ]
35
+        )
36
+          .evaluate(env)
37
+      ).to eq(10.0)
38
+    end
39
+
40
+    it 'returns an error if the function is not defined' do
41
+      env = Env.new
42
+      expect(AST::List.new([AST::Identifier.new("x")])
43
+        .evaluate(env))
44
+        .to eq(Error.new("Unbound variable x"))
45
+    end
46
+  end
47
+end

+ 2
- 2
spec/interpreter_spec.rb View File

@@ -26,7 +26,7 @@ module Chervil
26 26
       expect(interpret('(plus-one 2)', env).first).to eq(3.0)
27 27
     end
28 28
 
29
-    it 'doesn\'t leave variables bound after function execution' do
29
+    it "doesn't leave variables bound after function execution" do
30 30
       env = Env.new
31 31
       interpret('(define (plus-one x) (+ 1 x))', env)
32 32
       interpret('(plus-one 5)', env)
@@ -35,7 +35,7 @@ module Chervil
35 35
 
36 36
     it 'returns a type error for invalid operation' do
37 37
       expect(interpret('(+ 1 "hello")', Env.new).first).to eq(
38
-        Error.new("Expected an argument of type number but got string")
38
+        Error.new('Expected an argument of type number but got string')
39 39
       )
40 40
     end
41 41
   end

+ 22
- 14
spec/parser_spec.rb View File

@@ -26,9 +26,8 @@ module Chervil
26 26
 
27 27
     it 'parses an application' do
28 28
       expect(parse('(+ 1 2)').first).to eq(
29
-        AST::Application.new(
30
-          AST::Identifier.new('+'),
31
-          [AST::Number.new(1.0), AST::Number.new(2.0)]
29
+        AST::List.new(
30
+          [AST::Identifier.new('+'), AST::Number.new(1.0), AST::Number.new(2.0)]
32 31
         )
33 32
       )
34 33
     end
@@ -41,16 +40,22 @@ module Chervil
41 40
 
42 41
     it 'parses a nested expression' do
43 42
       expect(parse('(+ (+ 1 2) (- 3 4))').first).to eq(
44
-        AST::Application.new(
45
-          AST::Identifier.new('+'),
43
+        AST::List.new(
46 44
           [
47
-            AST::Application.new(
48
-              AST::Identifier.new('+'),
49
-              [AST::Number.new(1.0), AST::Number.new(2.0)]
45
+            AST::Identifier.new('+'),
46
+            AST::List.new(
47
+              [
48
+                AST::Identifier.new('+'),
49
+                AST::Number.new(1.0),
50
+                AST::Number.new(2.0)
51
+              ]
50 52
             ),
51
-            AST::Application.new(
52
-              AST::Identifier.new('-'),
53
-              [AST::Number.new(3.0), AST::Number.new(4.0)]
53
+            AST::List.new(
54
+              [
55
+                AST::Identifier.new('-'),
56
+                AST::Number.new(3.0),
57
+                AST::Number.new(4.0)
58
+              ]
54 59
             )
55 60
           ]
56 61
         )
@@ -65,9 +70,12 @@ module Chervil
65 70
             AST::Identifier.new('square'),
66 71
             [AST::Identifier.new('x')],
67 72
             [
68
-              AST::Application.new(
69
-                AST::Identifier.new('*'),
70
-                [AST::Identifier.new('x'), AST::Identifier.new('x')]
73
+              AST::List.new(
74
+                [
75
+                  AST::Identifier.new('*'),
76
+                  AST::Identifier.new('x'),
77
+                  AST::Identifier.new('x')
78
+                ]
71 79
               )
72 80
             ]
73 81
           )

Loading…
Cancel
Save