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
|