Skip to content

Commit

Permalink
ruby: use pattern matching, remove double negations, simplify try*
Browse files Browse the repository at this point in the history
  • Loading branch information
asarhaddon committed Aug 5, 2024
1 parent fb7effe commit ecdd391
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 235 deletions.
24 changes: 11 additions & 13 deletions impls/ruby/step2_eval.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,26 @@ def EVAL(ast, env)
#puts "EVAL: #{_pr_str(ast, true)}"

case ast
when Symbol
in Symbol
raise "'" + ast.to_s + "' not found" if not env.key? ast
return env[ast]
when List
when Vector
in Vector
return Vector.new ast.map{|a| EVAL(a, env)}
when Hash
in Hash
new_hm = {}
ast.each{|k,v| new_hm[k] = EVAL(v, env)}
return new_hm
else
return ast
end

# apply list
if ast.empty?
return ast
end

f = EVAL(ast[0], env)
args = ast.drop(1)
return f[*args.map{|a| EVAL(a, env)}]
in [a0, *]
f = EVAL(a0, env)
args = ast.drop(1)
return f[*args.map{|a| EVAL(a, env)}]

else # Empty list or scalar
return ast
end
end

# print
Expand Down
24 changes: 9 additions & 15 deletions impls/ruby/step3_env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,32 @@ def EVAL(ast, env)
end

case ast
when Symbol
in Symbol
return env.get(ast)
when List
when Vector
in Vector
return Vector.new ast.map{|a| EVAL(a, env)}
when Hash
in Hash
new_hm = {}
ast.each{|k,v| new_hm[k] = EVAL(v, env)}
return new_hm
else
return ast
end

# apply list
if ast.empty?
return ast
end

a0,a1,a2,a3 = ast
case a0
when :def!
in :def!, a1, a2
return env.set(a1, EVAL(a2, env))
when :"let*"
in :"let*", a1, a2
let_env = Env.new(env)
a1.each_slice(2) do |a,e|
let_env.set(a, EVAL(e, let_env))
end
return EVAL(a2, let_env)
else
in [a0, *]
f = EVAL(a0, env)
args = ast.drop(1)
return f[*args.map{|a| EVAL(a, env)}]

else # Empty list or scalar
return ast
end
end

Expand Down
39 changes: 16 additions & 23 deletions impls/ruby/step4_if_fn_do.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,53 +17,46 @@ def EVAL(ast, env)
end

case ast
when Symbol
in Symbol
return env.get(ast)
when List
when Vector
in Vector
return Vector.new ast.map{|a| EVAL(a, env)}
when Hash
in Hash
new_hm = {}
ast.each{|k,v| new_hm[k] = EVAL(v, env)}
return new_hm
else
return ast
end

# apply list
if ast.empty?
return ast
end

a0,a1,a2,a3 = ast
case a0
when :def!
in :def!, a1, a2
return env.set(a1, EVAL(a2, env))
when :"let*"
in :"let*", a1, a2
let_env = Env.new(env)
a1.each_slice(2) do |a,e|
let_env.set(a, EVAL(e, let_env))
end
return EVAL(a2, let_env)
when :do
in [:do, *]
ast[1..-2].map{|a| EVAL(a, env)}
return EVAL(ast[-1], env)
when :if
return EVAL(ast.last, env)
in [:if, a1, a2, *]
cond = EVAL(a1, env)
if not cond
return nil if a3 == nil
return EVAL(a3, env)
else
if cond
return EVAL(a2, env)
else
return EVAL(ast[3], env)
end
when :"fn*"
in :"fn*", a1, a2
return lambda {|*args|
EVAL(a2, Env.new(env, a1, List.new(args)))
}
else
in [a0, *]
f = EVAL(a0, env)
args = ast.drop(1)
return f[*args.map{|a| EVAL(a, env)}]

else # Empty list or scalar
return ast
end
end

Expand Down
37 changes: 15 additions & 22 deletions impls/ruby/step5_tco.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,41 @@ def EVAL(ast, env)
end

case ast
when Symbol
in Symbol
return env.get(ast)
when List
when Vector
in Vector
return Vector.new ast.map{|a| EVAL(a, env)}
when Hash
in Hash
new_hm = {}
ast.each{|k,v| new_hm[k] = EVAL(v, env)}
return new_hm
else
return ast
end

# apply list
if ast.empty?
return ast
end

a0,a1,a2,a3 = ast
case a0
when :def!
in :def!, a1, a2
return env.set(a1, EVAL(a2, env))
when :"let*"
in :"let*", a1, a2
let_env = Env.new(env)
a1.each_slice(2) do |a,e|
let_env.set(a, EVAL(e, let_env))
end
env = let_env
ast = a2 # Continue loop (TCO)
when :do
in [:do, *]
ast[1..-2].map{|a| EVAL(a, env)}
ast = ast.last # Continue loop (TCO)
when :if
in [:if, a1, a2, *]
cond = EVAL(a1, env)
if not cond
return nil if a3 == nil
ast = a3 # Continue loop (TCO)
else
if cond
ast = a2 # Continue loop (TCO)
else
ast = ast[3] # Continue loop (TCO)
end
when :"fn*"
in :"fn*", a1, a2
return Function.new(a2, env, a1) {|*args|
EVAL(a2, Env.new(env, a1, List.new(args)))
}
else
in [a0, *]
f = EVAL(a0, env)
args = ast.drop(1)
if f.class == Function
Expand All @@ -73,6 +63,9 @@ def EVAL(ast, env)
else
return f[*args.map{|a| EVAL(a, env)}]
end

else # Empty list or scalar
return ast
end

end
Expand Down
37 changes: 15 additions & 22 deletions impls/ruby/step6_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,51 +19,41 @@ def EVAL(ast, env)
end

case ast
when Symbol
in Symbol
return env.get(ast)
when List
when Vector
in Vector
return Vector.new ast.map{|a| EVAL(a, env)}
when Hash
in Hash
new_hm = {}
ast.each{|k,v| new_hm[k] = EVAL(v, env)}
return new_hm
else
return ast
end

# apply list
if ast.empty?
return ast
end

a0,a1,a2,a3 = ast
case a0
when :def!
in :def!, a1, a2
return env.set(a1, EVAL(a2, env))
when :"let*"
in :"let*", a1, a2
let_env = Env.new(env)
a1.each_slice(2) do |a,e|
let_env.set(a, EVAL(e, let_env))
end
env = let_env
ast = a2 # Continue loop (TCO)
when :do
in [:do, *]
ast[1..-2].map{|a| EVAL(a, env)}
ast = ast.last # Continue loop (TCO)
when :if
in [:if, a1, a2, *]
cond = EVAL(a1, env)
if not cond
return nil if a3 == nil
ast = a3 # Continue loop (TCO)
else
if cond
ast = a2 # Continue loop (TCO)
else
ast = ast[3] # Continue loop (TCO)
end
when :"fn*"
in :"fn*", a1, a2
return Function.new(a2, env, a1) {|*args|
EVAL(a2, Env.new(env, a1, List.new(args)))
}
else
in [a0, *]
f = EVAL(a0, env)
args = ast.drop(1)
if f.class == Function
Expand All @@ -73,6 +63,9 @@ def EVAL(ast, env)
else
return f[*args.map{|a| EVAL(a, env)}]
end

else # Empty list or scalar
return ast
end

end
Expand Down
Loading

0 comments on commit ecdd391

Please sign in to comment.