Просмотр исходного кода

Parse function definitions

master
Dylan Baker 5 лет назад
Родитель
Сommit
71b2364613
4 измененных файлов: 72 добавлений и 11 удалений
  1. 1
    0
      lib/chervil/ast.rb
  2. 15
    0
      lib/chervil/ast/function.rb
  3. 28
    5
      lib/chervil/parser.rb
  4. 28
    6
      spec/parser_spec.rb

+ 1
- 0
lib/chervil/ast.rb Просмотреть файл

5
     require "chervil/ast/application"
5
     require "chervil/ast/application"
6
     require "chervil/ast/boolean"
6
     require "chervil/ast/boolean"
7
     require "chervil/ast/definition"
7
     require "chervil/ast/definition"
8
+    require "chervil/ast/function"
8
     require "chervil/ast/identifier"
9
     require "chervil/ast/identifier"
9
     require "chervil/ast/number"
10
     require "chervil/ast/number"
10
     require "chervil/ast/string"
11
     require "chervil/ast/string"

+ 15
- 0
lib/chervil/ast/function.rb Просмотреть файл

1
+module Chervil::AST
2
+  class Function
3
+    attr_reader :params
4
+    attr_reader :body
5
+
6
+    def initialize(params, body)
7
+      @params = params
8
+      @body = body
9
+    end
10
+
11
+    def ==(other)
12
+      @params == other.params && @body == other.body
13
+    end
14
+  end
15
+end

+ 28
- 5
lib/chervil/parser.rb Просмотреть файл

28
       eat(:lparen)
28
       eat(:lparen)
29
 
29
 
30
       if @current_token.type == :identifier && @current_token.value == 'define'
30
       if @current_token.type == :identifier && @current_token.value == 'define'
31
-        eat(:identifier)
32
-        name = identifier
33
-        value = expr
34
-        eat(:rparen)
35
-        return AST::Definition.new(name, value)
31
+        return definition
36
       end
32
       end
37
 
33
 
38
       expression = expr
34
       expression = expr
47
       AST::Application.new(expression, args)
43
       AST::Application.new(expression, args)
48
     end
44
     end
49
 
45
 
46
+    def definition
47
+      eat(:identifier) # the `define`
48
+      if @current_token.type == :identifier
49
+        name = identifier
50
+        value = expr
51
+        eat(:rparen)
52
+        AST::Definition.new(name, value)
53
+      elsif @current_token.type == :lparen
54
+        eat(:lparen)
55
+        name = identifier
56
+        params = Array.new
57
+        until [:rparen, :eof].include?(@current_token.type)
58
+          params << expr
59
+        end
60
+        eat(:rparen)
61
+
62
+        body = Array.new
63
+        until [:rparen, :eof].include?(@current_token.type)
64
+          body << expr
65
+        end
66
+
67
+        eat(:rparen)
68
+
69
+        AST::Definition.new(name, AST::Function.new(params, body))
70
+      end
71
+    end
72
+
50
     def identifier
73
     def identifier
51
       identifier = eat(:identifier)
74
       identifier = eat(:identifier)
52
       AST::Identifier.new(identifier.value)
75
       AST::Identifier.new(identifier.value)

+ 28
- 6
spec/parser_spec.rb Просмотреть файл

18
       expect(parse('+').first).to eq(AST::Identifier.new('+'))
18
       expect(parse('+').first).to eq(AST::Identifier.new('+'))
19
     end
19
     end
20
 
20
 
21
+    it 'parses booleans' do
22
+      expect(parse('#t #f')).to eq(
23
+        [
24
+          AST::Boolean.new(true),
25
+          AST::Boolean.new(false),
26
+        ]
27
+      )
28
+    end
29
+
21
     it 'parses an application' do
30
     it 'parses an application' do
22
       expect(parse('(+ 1 2)').first).to eq(
31
       expect(parse('(+ 1 2)').first).to eq(
23
         AST::Application.new(
32
         AST::Application.new(
57
       )
66
       )
58
     end
67
     end
59
 
68
 
60
-    it 'parses booleans' do
61
-      expect(parse('#t #f')).to eq(
62
-        [
63
-          AST::Boolean.new(true),
64
-          AST::Boolean.new(false),
65
-        ]
69
+    it 'parses a function definition' do
70
+      expect(parse('(define (square x) (* x x))').first).to eq(
71
+        AST::Definition.new(
72
+          AST::Identifier.new("square"),
73
+          AST::Function.new(
74
+            [
75
+              AST::Identifier.new("x")
76
+            ],
77
+            [
78
+              AST::Application.new(
79
+                AST::Identifier.new("*"),
80
+                [
81
+                  AST::Identifier.new("x"),
82
+                  AST::Identifier.new("x"),
83
+                ]
84
+              )
85
+            ]
86
+          )
87
+        )
66
       )
88
       )
67
     end
89
     end
68
   end
90
   end

Загрузка…
Отмена
Сохранить