File: lambda_calculus.treetop

package info (click to toggle)
ruby-treetop 1.6.14-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 956 kB
  • sloc: ruby: 8,918; makefile: 5
file content (132 lines) | stat: -rw-r--r-- 2,677 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
grammar LambdaCalculus
  include Arithmetic

  rule program
    expression more_expressions:(';' space expression)* {
      def eval(env={})
        env = env.clone
        last_eval = nil
        expressions.each do |exp|
          last_eval = exp.eval(env)
        end
        last_eval
      end
      
      def expressions
        [expression] + more_expressions.elements.map {|elt| elt.expression}
      end
    }
  end

  rule expression
    definition / conditional / application / function / super
  end
  
  rule definition
    'def' space variable space expression {
      def eval(env)
        env[variable.name] = expression.eval(env)
      end
    }
  end
  
  rule conditional
    'if' space '(' space condition:expression space ')' space
    true_case:expression space 'else' space false_case:expression {
      def eval(env)
        if condition.eval(env)
          true_case.eval(env)
        else
          false_case.eval(env)
        end
      end
    }
  end
  
  rule primary
    application / super
  end

  rule application
    operator space expression <Application> {
      def eval(env={})
        left_associative_apply(operator.eval(env), env)
      end
      
      def left_associative_apply(operator, env)
        if expression.instance_of?(Application)
          expression.left_associative_apply(operator.apply(expression.operator.eval(env)), env)
        else
          operator.apply(expression.eval(env))
        end
      end
      
      def to_s(env={})
        operator.to_s(env) + ' ' + expression.to_s(env)
      end
    }
  end
  
  rule operator
    function / variable
  end
  
  rule non_application
    function / variable
  end
  
  rule function
    '\\' param:variable '(' body:expression ')' {
      class Closure
        attr_reader :env, :function
        
        def initialize(function, env)
          @function = function
          @env = env
        end
      
        def apply(arg)
          function.body.eval(function.param.bind(arg, env))
        end
      
        def to_s(other_env={})
          "\\#{function.param.to_s}(#{function.body.to_s(other_env.merge(env))})"
        end
      end
      
      def eval(env={})
        Closure.new(self, env)
      end
      
      def to_s(env={})
        eval(env).to_s
      end
    }
  end
  
  rule variable
    !keyword (
      super {
        def bind(value, env)
          env.merge(name => value)
        end

        def to_s(env={})
          env.has_key?(name) ? env[name].to_s : name
      end
      }
    )
  end
  
  rule keyword
    ('if' / 'else') !non_space_char
  end
  
  rule non_space_char
    ![ \n] .
  end
  
  rule space
    [ \n]*
  end
end