Browse Source

Allow recursive functions & closures

master
Dylan Baker 5 years ago
parent
commit
1954d89211

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

@@ -19,7 +19,7 @@ module Chervil::AST
19 19
         if function.nil?
20 20
           ::Chervil::Error.new("Unbound variable #{@expr.name}")
21 21
         else
22
-          function.call(@arguments.map { |arg| arg.evaluate(env) })
22
+          function.call(@arguments.map { |arg| arg.evaluate(env) }, env)
23 23
         end
24 24
       end
25 25
     end

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

@@ -18,12 +18,11 @@ module Chervil::AST
18 18
       self
19 19
     end
20 20
 
21
-    def call(args)
21
+    def call(args, env)
22 22
       unless @params.size == args.size
23 23
         raise "Expected #{params.size} arguments but received #{args.size}"
24 24
       end
25 25
 
26
-      env = ::Chervil::Env.new
27 26
       @params.zip(args).each do |key, value|
28 27
         env.set(key.name, value)
29 28
       end

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

@@ -17,7 +17,8 @@ module Chervil
17 17
             )
18 18
           ],
19 19
         ).call(
20
-          [AST::Number.new(5.0)]
20
+          [AST::Number.new(5.0)],
21
+          Env.new
21 22
         )
22 23
       ).to eq(25.0)
23 24
     end

+ 1
- 1
spec/env_spec.rb View File

@@ -2,7 +2,7 @@ module Chervil
2 2
   RSpec.describe Env do
3 3
     it 'has arithmetic from core' do
4 4
       env = Env.new
5
-      expect(env.get("+").call([1, 2])).to eq(3)
5
+      expect(env.get("+").call([1, 2], env)).to eq(3)
6 6
     end
7 7
 
8 8
     it 'inherits from parent env' do

+ 13
- 0
spec/interpreter_spec.rb View File

@@ -12,5 +12,18 @@ module Chervil
12 12
       expect(env.get("x")).to eq(AST::Number.new(5.0))
13 13
       expect(interpret('x', env).first).to eq(5.0)
14 14
     end
15
+
16
+    it 'interprets a recursive function' do
17
+      env = Env.new
18
+      interpret('(define (fact x) (if (= x 0) 1 (* x (fact (- x 1)))))', env)
19
+      expect(interpret('(fact 5)', env).first).to eq(120.0)
20
+    end
21
+
22
+    it 'supports closures' do
23
+      env = Env.new
24
+      interpret('(define one 1)', env)
25
+      interpret('(define (plus-one x) (+ x one))', env)
26
+      expect(interpret('(plus-one 2)', env).first).to eq(3.0)
27
+    end
15 28
   end
16 29
 end

Loading…
Cancel
Save