-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathruboty-parse_ruby.rb
85 lines (74 loc) · 2.22 KB
/
ruboty-parse_ruby.rb
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
require 'open3'
module Ruboty
module Handlers
class ParseRuby < Base
KNOWN_RUBY_VERSIONS = 18..27
KNOWN_PARSERS = %w[ripper sexp tokenize lex rubyvm] + KNOWN_RUBY_VERSIONS.map {|v| "parser#{v}"}
KNOWN_RUBY_VERSIONS.each do |v|
require "parser/ruby#{v}"
end
require 'ripper'
require 'pp'
on(
/(?<with_parse>parse\s)?(?:(?<parser>#{Regexp.union(*KNOWN_PARSERS)})\s)?(?<code>.+)/im,
name: 'parse',
description: "Parse Ruby code and response AST",
)
on(
/syntax-check (?<code>.+)/im,
name: 'syntax_check',
description: 'Check the syntax of the given Ruby code with parser gem',
)
on(
/-?cwe? (?<code>.+)/im,
name: 'cw',
description: 'Run ruby -cw',
)
def parse(message)
m = message.match_data
parser = m['parser']
code = m['code']
with_parse = m['with_parse']
return if !with_parse && !parser
obj = parse_code(parser, code)
message.reply wrap_codeblock(obj.pretty_inspect)
end
def syntax_check(message)
code = message.match_data['code']
result = KNOWN_RUBY_VERSIONS.map do |v|
err_or_ast = parse_code("parser#{v}", code)
ok = !err_or_ast.is_a?(Exception)
"#{v}: #{ok ? 'ok' : err_or_ast}"
end
message.reply result.join "\n"
end
def cw(message)
code = message.match_data['code']
out, _status = Open3.capture2e("ruby", '-cwve', code)
message.reply wrap_codeblock(out)
end
private def parse_code(parser, code)
case parser
when 'ripper', 'sexp', nil
Ripper.sexp(code)
when 'tokenize'
Ripper.tokenize(code)
when 'lex'
Ripper.lex(code)
when /parser(?<version>\d+)/
v = Regexp.last_match['version']
Parser.const_get(:"Ruby#{v}").parse(code)
when 'rubyvm'
RubyVM::AbstractSyntaxTree.parse(code)
else
raise 'unreachable'
end
rescue SyntaxError, Parser::SyntaxError => ex
ex
end
private def wrap_codeblock(str)
"```\n#{str.chomp}\n```"
end
end
end
end