Skip to content

Instantly share code, notes, and snippets.

@oprypin
Last active August 24, 2016 23:02
Show Gist options
  • Save oprypin/b4f150b0d22e9e3ee2dff3bcf8ec8cb5 to your computer and use it in GitHub Desktop.
Save oprypin/b4f150b0d22e9e3ee2dff3bcf8ec8cb5 to your computer and use it in GitHub Desktop.
Power Assert 2
require "compiler/crystal/syntax"
include Crystal
class AssertToSVisitor < ToSVisitor
getter locations = [] of Int32
def visit_any(node)
if node.class.name.ends_with?("Literal") || node.is_a? Path
@str << node.to_s
return false
end
if (loc = node.location)
@str << "(__" << locations.size << "=("
locations << case node
when Call
node.name_column_number
when Cast, NilableCast, IsA, RespondsTo
# TODO these should provide name_column_number
if node.responds_to?(:obj) # TODO why is this needed? bug?
loc.column_number + node.obj.to_s.size + 1
else raise "impossible"; end
else
loc.column_number
end - 1
end
super
end
def end_visit_any(node)
super
@str << "))"
end
end
src = ARGV[0].gsub('\n', ' ')
visitor = AssertToSVisitor.new(io = MemoryIO.new)
Crystal::Parser.parse(src).accept(visitor)
puts "unless #{io}"
puts " puts #{src.inspect}"
unless visitor.locations.empty?
vals = visitor.locations.each_index.map { |i| "__#{i}" }
puts %{ \
__val = {#{vals.join(", ")}}
(__loc = #{visitor.locations}).size.times do |i|
pipes = (0..__loc.max).map { |c| __loc.includes?(c) ? '|' : ' ' }.join
puts pipes if i == 0
result = pipes[0...__loc.shift] + __val[i].inspect
result += (pipes[result.size..-1] rescue "")
puts result
end}
end
puts "end"
print "#" * 80
macro assert(expr)
{% puts o = run("./assert", expr) %}
{{ o }}
end
foo = "foo"
assert %{foo.index('o') == 1 + 2}
unless (__0=(((__1=((__2=(foo)).index('o')))) == ((__3=(1 + 2)))))
puts "foo.index('o') == 1 + 2"
__val = {__0, __1, __2, __3}
(__loc = [15, 4, 0, 20]).size.times do |i|
pipes = (0..__loc.max).map { |c| __loc.includes?(c) ? '|' : ' ' }.join
puts pipes if i == 0
result = pipes[0...__loc.shift] + __val[i].inspect
result += (pipes[result.size..-1] rescue "")
puts result
end
end
################################################################################
foo.index('o') == 1 + 2
| | | |
| | false|
| 1 |
"foo" |
3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment