endlessruby 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +1 -0
- data/Manifest.txt +3 -2
- data/README.rdoc +28 -5
- data/bin/endlessruby +1 -1
- data/lib/endlessruby.rb +221 -159
- data/lib/endlessruby/{extensions.rb → custom_require.rb} +28 -41
- data/lib/endlessruby/main.rb +9 -15
- data/spec/build_self_spec.rb +2 -2
- data/spec/endlessruby_spec.rb +2 -0
- data/spec/require_spec.rb +8 -0
- data/spec/semicolon_spec.rb +11 -2
- data/spec/simply_spec.rb +16 -0
- data/spec/use_end_case_spec.rb +27 -0
- data/src/endlessruby.er +213 -147
- data/src/endlessruby/{extensions.er → custom_require.er} +27 -37
- data/src/endlessruby/main.er +9 -11
- metadata +12 -45
@@ -13,62 +13,49 @@ module Kernel
|
|
13
13
|
# pathが./または/で以外で始まる場合は$LOAD_PATHと$:をそれぞれ参照してpathを探します。
|
14
14
|
# もしpathがそれらで始まる場合はそれぞれ参照しません。(つまり通常のrequireの動作と同じです)
|
15
15
|
def require path
|
16
|
-
at = caller
|
17
16
|
endlessruby_original_require path
|
18
17
|
rescue SyntaxError, LoadError
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
|
19
|
+
load = lambda do |path, abspath|
|
20
|
+
|
21
|
+
if !File.exist?(abspath) || File.directory?(abspath)
|
22
|
+
if File.exist? "#{abspath}.er"
|
23
|
+
abspath = "#{abspath}.er"
|
24
24
|
else
|
25
|
-
$@ = at
|
26
25
|
raise LoadError, "no such file to load -- #{path}"
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
if
|
31
|
-
|
29
|
+
return false if $".include? abspath
|
30
|
+
|
31
|
+
if File.directory? abspath
|
32
32
|
raise LoadError, "Is a directory - #{path}"
|
33
33
|
end
|
34
34
|
|
35
|
-
open(
|
36
|
-
|
37
|
-
|
38
|
-
rescue Exception => e
|
39
|
-
$@ = at
|
40
|
-
raise e
|
41
|
-
end
|
35
|
+
open(abspath) do |file|
|
36
|
+
EndlessRuby.ereval file.read, TOPLEVEL_BINDING, abspath
|
37
|
+
$" << abspath
|
42
38
|
return true
|
43
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
case path
|
43
|
+
when /^\~(.*?)$/
|
44
|
+
load.call path, File.join(ENV['HOME'], $1)
|
45
|
+
when /^\.\/.*?$/, /^\/.*?$/
|
46
|
+
load.call path, path
|
44
47
|
else
|
45
48
|
is_that_dir = false
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
next is_that_dir = true if File.directory? real_path
|
57
|
-
open(real_path) do |file|
|
58
|
-
begin
|
59
|
-
EndlessRuby.ereval file.read, TOPLEVEL_BINDING, real_path
|
60
|
-
rescue Exception => e
|
61
|
-
$@ = at
|
62
|
-
raise e
|
63
|
-
end
|
49
|
+
$:.each do |load_path|
|
50
|
+
abspath = File.join load_path, path
|
51
|
+
begin
|
52
|
+
return load.call path, abspath
|
53
|
+
rescue SyntaxError => e
|
54
|
+
$stderr.puts "*ENDLESSRUBY BUG*"
|
55
|
+
raise e
|
56
|
+
rescue LoadError => e
|
57
|
+
raise e if load_path == $:.last
|
64
58
|
end
|
65
|
-
return true
|
66
|
-
end
|
67
|
-
$@ = at
|
68
|
-
if is_that_dir
|
69
|
-
raise LoadError, "Is a directory - #{path}"
|
70
|
-
else
|
71
|
-
raise LoadError, "no such file to load -- #{path}"
|
72
59
|
end
|
73
60
|
end
|
74
61
|
end
|
data/lib/endlessruby/main.rb
CHANGED
@@ -9,23 +9,14 @@ module EndlessRuby::Main
|
|
9
9
|
|
10
10
|
# er ファイルから読み込みそれをピュアなRubyにコンパイルしてrbに書き出します
|
11
11
|
def compile er, rb
|
12
|
-
|
13
|
-
open(rb, "w") do |rbfile|
|
14
|
-
rbfile.write ER2PR(erfile.read)
|
15
|
-
end
|
16
|
-
end
|
12
|
+
ER2PR({ :in => { :any => er }, :out => { :any => rb } })
|
17
13
|
end
|
18
14
|
|
19
15
|
# rbファイルを読み込みそれからすべてのendを取り除きます。
|
20
16
|
def decompile rb, er
|
21
|
-
|
22
|
-
open(er, "w") do |erfile|
|
23
|
-
erfile.write PR2ER(rbfile.read)
|
24
|
-
end
|
25
|
-
end
|
17
|
+
PR2ER({ :in => { :any => rb }, :out => { :any => er } })
|
26
18
|
end
|
27
19
|
|
28
|
-
|
29
20
|
# EndlessRuby::Main.main と同じ動作をします。このモジュールをincludeした場合に使用します。
|
30
21
|
def endlessruby argv
|
31
22
|
EndlessRuby::Main.main argv
|
@@ -48,19 +39,22 @@ module EndlessRuby::Main
|
|
48
39
|
}
|
49
40
|
|
50
41
|
parser = OptionParser.new do |opts|
|
51
|
-
|
42
|
+
|
43
|
+
opts.version = EndlessRuby::VERSION
|
44
|
+
|
45
|
+
opts.on '-o OUT', 'appoint output directory.' do |out|
|
52
46
|
options[:out] = out
|
53
47
|
end
|
54
48
|
|
55
|
-
opts.on '-c', '--compile' do |c|
|
49
|
+
opts.on '-c', '--compile', 'compile endlessruby source code to pure ruby' do |c|
|
56
50
|
options[:compile] = true
|
57
51
|
end
|
58
52
|
|
59
|
-
opts.on '-d', '--decompile' do |d|
|
53
|
+
opts.on '-d', '--decompile', 'decompile pure ruby source code to endless ruby' do |d|
|
60
54
|
options[:decompile] = true
|
61
55
|
end
|
62
56
|
|
63
|
-
opts.on '-r' do |r|
|
57
|
+
opts.on '-r', 'unimplemented' do |r|
|
64
58
|
options[:recursive] = true
|
65
59
|
end
|
66
60
|
end
|
data/spec/build_self_spec.rb
CHANGED
@@ -12,8 +12,8 @@ describe EndlessRuby, "must can compile self" do
|
|
12
12
|
"#{lib}/endlessruby.rb",
|
13
13
|
"#{src}/endlessruby/main.er",
|
14
14
|
"#{lib}/endlessruby/main.rb",
|
15
|
-
"#{src}/endlessruby/
|
16
|
-
"#{lib}/endlessruby/
|
15
|
+
"#{src}/endlessruby/custom_require.er",
|
16
|
+
"#{lib}/endlessruby/custom_require.rb",
|
17
17
|
"#{src}/er.er",
|
18
18
|
"#{bin}/endlessruby",
|
19
19
|
]
|
data/spec/endlessruby_spec.rb
CHANGED
data/spec/require_spec.rb
CHANGED
@@ -26,4 +26,12 @@ describe "require" do
|
|
26
26
|
TestData.test_data.should == "ruby script"
|
27
27
|
end
|
28
28
|
|
29
|
+
it "require ellipsis of 'er' and exist same name directory" do
|
30
|
+
|
31
|
+
require 'test_data/exist_same_name_directory'
|
32
|
+
|
33
|
+
$test_data.should == "exist same name directory"
|
34
|
+
TestData.test_data.should == "exist same name directory"
|
35
|
+
end
|
36
|
+
|
29
37
|
end
|
data/spec/semicolon_spec.rb
CHANGED
@@ -7,8 +7,17 @@ describe "split with semicolon lines is inner lines" do
|
|
7
7
|
def method; statements; end
|
8
8
|
DEFINE
|
9
9
|
<<DEFINE.chomp!
|
10
|
-
def method
|
11
|
-
|
10
|
+
def method; statements; end
|
11
|
+
DEFINE
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
it "example" do
|
16
|
+
ER2RB(<<DEFINE).should ==
|
17
|
+
def method; statements
|
18
|
+
DEFINE
|
19
|
+
<<DEFINE.chomp!
|
20
|
+
def method; statements
|
12
21
|
end
|
13
22
|
DEFINE
|
14
23
|
|
data/spec/simply_spec.rb
CHANGED
@@ -461,6 +461,22 @@ DEFINE
|
|
461
461
|
|
462
462
|
end
|
463
463
|
|
464
|
+
describe "for expression case" do
|
465
|
+
|
466
|
+
it "for" do
|
467
|
+
ER2RB(<<DEFINE).should ==
|
468
|
+
for i in enu
|
469
|
+
pass
|
470
|
+
DEFINE
|
471
|
+
<<DEFINE.chomp!
|
472
|
+
for i in enu
|
473
|
+
pass
|
474
|
+
end
|
475
|
+
DEFINE
|
476
|
+
end
|
477
|
+
|
478
|
+
end
|
479
|
+
|
464
480
|
describe "exception expression case" do
|
465
481
|
|
466
482
|
it "try only" do
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe "use end case" do
|
4
|
+
|
5
|
+
it "example" do
|
6
|
+
ER2RB(<<DEFINE).should ==
|
7
|
+
def m
|
8
|
+
if true
|
9
|
+
case a
|
10
|
+
when b then 1
|
11
|
+
end
|
12
|
+
else
|
13
|
+
end
|
14
|
+
DEFINE
|
15
|
+
<<DEFINE.chomp!
|
16
|
+
def m
|
17
|
+
if true
|
18
|
+
case a
|
19
|
+
when b then 1
|
20
|
+
end
|
21
|
+
else
|
22
|
+
end
|
23
|
+
end
|
24
|
+
DEFINE
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
data/src/endlessruby.er
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
$:.unshift(File.dirname(__FILE__)) unless
|
5
5
|
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
6
6
|
|
7
|
-
require 'endlessruby/
|
7
|
+
require 'endlessruby/custom_require'
|
8
|
+
require "tempfile"
|
9
|
+
require "irb"
|
8
10
|
|
9
11
|
# EndlessRubyはRubyをendを取り除いて書けます。
|
10
12
|
#
|
@@ -34,179 +36,243 @@ require 'endlessruby/extensions'
|
|
34
36
|
module EndlessRuby
|
35
37
|
|
36
38
|
# EndlessRuby のバージョンです
|
37
|
-
VERSION = "0.0
|
39
|
+
VERSION = "0.1.0"
|
38
40
|
|
39
41
|
extend self
|
40
42
|
|
41
|
-
private
|
42
|
-
|
43
|
-
# 内部で使用します。空業かどうか判定します。
|
44
|
-
def blank_line? line
|
45
|
-
return true unless line
|
46
|
-
(line.chomp.gsub /\s+?/, '') == ""
|
47
|
-
|
48
|
-
# 内部で使用します。インデントを取り除きます
|
49
|
-
def unindent line
|
50
|
-
line =~ /^\s*?(\S.*?)$/
|
51
|
-
$1
|
52
|
-
# 内部で使用します。インデントします
|
53
|
-
def indent line, level, indent=" "
|
54
|
-
"#{indent * level}#{line}"
|
55
|
-
|
56
|
-
# 内部で使用します。インデントの数を数えます。
|
57
|
-
def indent_count line, indent=" "
|
58
|
-
return 0 unless line
|
59
|
-
if line =~ /^#{indent}(.*?)$/
|
60
|
-
1 + (indent_count $1, indent)
|
61
|
-
else
|
62
|
-
0
|
63
|
-
|
64
|
-
# 内部で使用します。ブロックを作るキーワード群です。
|
65
|
-
BLOCK_KEYWORDS = [
|
66
|
-
[/^if(:?\s|\().*?$/, /^elsif(:?\s|\().*?$/, /^else(?:$|\s+)/],
|
67
|
-
[/^unless(:?\s|\().*?$/, /^elsif(:?\s|\().*?$/, /^else(?:$|\s+)/],
|
68
|
-
[/^while(:?\s|\().*?$/],
|
69
|
-
[/^until(:?\s|\().*?$/],
|
70
|
-
[/^case(:?\s|\().*?$/, /^when(:?\s|\().*?$/, /^else(?:$|\s+)/],
|
71
|
-
[/^def\s.*?$/, /^rescue(:?$|\s|\().*?$/, /^else(?:$|\s+)/, /^ensure(?:$|\s+)/],
|
72
|
-
[/^class\s.*?$/],
|
73
|
-
[/^module\s.*?$/],
|
74
|
-
[/^begin(?:$|\s+)/, /^rescue(:?$|\s|\().*?$/, /^else(?:$|\s+)/, /^ensure(?:$|\s+)/],
|
75
|
-
[/^.*?\s+do(:?$|\s|\|)/]
|
76
|
-
]
|
77
|
-
|
78
43
|
public
|
79
44
|
|
80
45
|
# 文字列をEndlessRubyの構文として実行します。引数の意味はKernel#evalと同じです
|
81
46
|
def ereval(src, binding=TOPLEVEL_BINDING, filename=__FILE__, lineno=1)
|
82
|
-
at = caller
|
83
47
|
eval(ER2PR(src), binding, filename, lineno)
|
84
|
-
rescue Exception => e
|
85
|
-
$@ = at
|
86
|
-
raise e
|
87
48
|
|
88
|
-
# Ruby
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
49
|
+
# EndlessRubyの構文をピュアなRubyの構文に変換します。<br />
|
50
|
+
# options: オプションを表すHashまたはto_hashを実装したオブジェクト、構文を読み出すIOまたはto_ioを実装したオブジェクト、EndlessRubyの構文を表すStringまたはto_strを実装したオブジェクト、またはファイルのパス<br />
|
51
|
+
# optionsが文字列ならばそれをピュアなRubyの構文にします。それがIOならばIOから読み出してそれをピュアなRubyの構文にします。<br />
|
52
|
+
# ファイルのパスならばそのファイルかあ読み込みます
|
53
|
+
# それがHashならばそれはオプションです。それぞれHashを指定します。<br />
|
54
|
+
# options: {
|
55
|
+
# in: {
|
56
|
+
# io: optionsにIOを指定した場合と同じです
|
57
|
+
# any: それが存在するファイルのパスを表す文字列ならばそのファイルから読み出します。この場合のanyはoptionsにそのような文字列を指定するのと同じ意味です。
|
58
|
+
# そうでない文字列ならばそれ自体をEndlessRubyの構文として読み出します。この場合のanyはoptionsに文字列を指定するのと同じ意味です。
|
59
|
+
# それがIOならばそのIOから読み出します。この場合のany はin.ioを直接指定するのと同じです。
|
60
|
+
# }
|
61
|
+
# out: {
|
62
|
+
# io: このIOに結果を書き出します。
|
63
|
+
# any: ファイルのパスかIOです。ファイルのパスならばそのファイルに書き出します。IOならばそのIOに書き出します。
|
64
|
+
# }
|
65
|
+
# decompile: trueならばコンパイルではなくてでコンパイルします。
|
66
|
+
# }
|
67
|
+
#
|
68
|
+
# opts[:out][:io] には書き出すioを指定します。<br />
|
69
|
+
# from a file on disk:<br />
|
70
|
+
# EndlessRuby.ER2RB("filename.er")
|
71
|
+
# <br />
|
72
|
+
# from string that is source code:<br />
|
73
|
+
# EndlessRuby.ER2RB(<<DEFINE)
|
74
|
+
# # endlessruby syntax
|
75
|
+
# DEFINE
|
76
|
+
# <br />
|
77
|
+
# from IO:<br />
|
78
|
+
# file = open 'filename.er'
|
79
|
+
# EndlessRuby.ER2RB(file)
|
80
|
+
#
|
81
|
+
# appoint input file and output file:
|
82
|
+
# ER2PR({ :in => { :any => 'filename.er' }, :out => { :any => 'filename.rb' } })
|
83
|
+
# ER2PR({ :in => { :io => in_io }, :out => { :io => out_io } })
|
84
|
+
def endless_ruby_to_pure_ruby options
|
85
|
+
converting_helper options
|
86
|
+
|
87
|
+
alias to_pure_ruby endless_ruby_to_pure_ruby
|
88
|
+
alias ER2PR endless_ruby_to_pure_ruby
|
89
|
+
alias ER2RB endless_ruby_to_pure_ruby
|
94
90
|
|
91
|
+
# Rubyの構文をEndlessRubyの構文に変換します。optionsはendlessruby_to_pure_rubyと同じです。
|
92
|
+
def pure_ruby_to_endless_ruby options
|
93
|
+
options = merge_options options
|
94
|
+
options[:decompile] = true
|
95
|
+
converting_helper options
|
95
96
|
|
96
97
|
alias RB2ER pure_ruby_to_endless_ruby
|
97
98
|
alias PR2ER pure_ruby_to_endless_ruby
|
98
99
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
pure << (currently_line = endless[i])
|
107
|
-
|
108
|
-
if currently_line =~ /(.*)(?:^|(?:(?!\\).))\#(?!\{).*$/
|
109
|
-
currently_line = $1
|
110
|
-
|
111
|
-
if blank_line? currently_line
|
112
|
-
i += 1
|
113
|
-
next
|
114
|
-
|
115
|
-
# ブロックを作らない構文なら単に無視する
|
116
|
-
next i += 1 unless BLOCK_KEYWORDS.any? { |k| k[0] =~ unindent(currently_line) }
|
117
|
-
|
118
|
-
# ブロックに入る
|
119
|
-
keyword = BLOCK_KEYWORDS.each { |k| break k if k[0] =~ unindent(currently_line) }
|
120
|
-
|
121
|
-
currently_indent_depth = indent_count currently_line
|
122
|
-
base_indent_depth = currently_indent_depth
|
123
|
-
|
124
|
-
inner_statements = []
|
125
|
-
# def method1
|
126
|
-
# statemetns
|
127
|
-
# # document of method2
|
128
|
-
# def method2
|
129
|
-
# statements
|
130
|
-
# のような場合にコメントの部分はmethod1内に含まないようにする。
|
131
|
-
# def method1
|
132
|
-
# statemetns
|
133
|
-
# # comment
|
134
|
-
# return
|
135
|
-
# のような場合と区別するため。
|
136
|
-
comment_count = 0
|
137
|
-
in_here_document = nil
|
138
|
-
while i < endless.length
|
139
|
-
|
140
|
-
inner_currently_line = endless[i + 1]
|
141
|
-
|
142
|
-
if inner_currently_line =~ /(.*)(?:^|(?:(?!\\).))\#(?!\{).*$/
|
143
|
-
if blank_line?($1) && currently_indent_depth >= indent_count(inner_currently_line)
|
144
|
-
comment_count += 1
|
145
|
-
inner_currently_line = $1
|
146
|
-
elsif blank_line? inner_currently_line
|
147
|
-
comment_count += 1
|
148
|
-
|
149
|
-
if blank_line? inner_currently_line
|
150
|
-
inner_statements << endless[i + 1]
|
151
|
-
i += 1
|
152
|
-
next
|
100
|
+
private
|
101
|
+
|
102
|
+
def merge_options options
|
103
|
+
|
104
|
+
opts = {
|
105
|
+
:in => {}, :out => {}
|
106
|
+
}
|
153
107
|
|
154
|
-
|
108
|
+
if options.respond_to? :to_hash
|
109
|
+
opts = opts.merge options.to_hash
|
110
|
+
elsif options.respond_to?(:to_io) || options.respond_to?(:to_str)
|
111
|
+
opts[:in][:any] = options
|
112
|
+
else
|
113
|
+
raise ArgumentError, "options is IO, String, or Hash"
|
114
|
+
|
115
|
+
if opts[:in][:any]
|
116
|
+
if opts[:in][:any].respond_to?(:to_str) && File.exist?(opts[:in][:any].to_str) # from a file on the disk.
|
117
|
+
opts[:in] = {
|
118
|
+
:io => (in_io = open opts[:in][:any].to_str),
|
119
|
+
:ensure => proc { in_io.close }
|
120
|
+
}
|
121
|
+
elsif opts[:in][:any].respond_to? :to_io # from IO that can read source code.
|
122
|
+
opts[:in] = {
|
123
|
+
:io => options.to_io,
|
124
|
+
:ensure => proc {}
|
125
|
+
}
|
126
|
+
elsif opts[:in][:any].respond_to? :to_str # from String that is source code.
|
127
|
+
in_io = Tempfile.new "endlessruby from temp file"
|
128
|
+
in_io.write options.to_str
|
129
|
+
in_io.seek 0
|
130
|
+
opts[:in] = {
|
131
|
+
:io => in_io,
|
132
|
+
:ensure => proc { in_io.close }
|
133
|
+
}
|
134
|
+
else
|
135
|
+
raise ArgumentError, "options[:in][:any] is IO, String which is path, or String which is source code"
|
136
|
+
|
137
|
+
opts[:in][:any] = nil
|
138
|
+
|
139
|
+
if opts[:out][:any]
|
140
|
+
if opts[:out][:any].respond_to?(:to_str) # to a file on the disk.
|
141
|
+
opts[:out] = {
|
142
|
+
:io => (out_io = open opts[:out][:any].to_str, "w+"),
|
143
|
+
:ensure => proc { out_io.close }
|
144
|
+
}
|
145
|
+
elsif opts[:out][:any].respond_to? :to_io # to IO that can read source code.
|
146
|
+
opts[:out] = {
|
147
|
+
:io => options.to_io,
|
148
|
+
:ensure => proc {}
|
149
|
+
}
|
150
|
+
else
|
151
|
+
raise ArgumentError, "options[:out][:any] is IO, or String which is Path"
|
152
|
+
elsif !opts[:out][:io]
|
153
|
+
opts[:out] = { :io => (out_io = Tempfile.new("endlessruby pure temp file")), :ensure => proc { out_io.close } }
|
155
154
|
|
156
|
-
|
157
|
-
|
158
|
-
comment_count = 0
|
155
|
+
opts[:out][:any] = nil
|
156
|
+
opts
|
159
157
|
|
160
|
-
|
161
|
-
|
158
|
+
def converting_helper options
|
159
|
+
opts = merge_options options
|
162
160
|
|
163
|
-
|
164
|
-
if (in_here_document[0] == '' && inner_currently_line =~ /^#{in_here_document[1]}\s*$/) || # <<DEFINE case
|
165
|
-
(in_here_document[0] == '-' && inner_currently_line =~ /^\s*#{in_here_document[1]}\s*$/) # <<-DEFINE case
|
166
|
-
in_here_document = nil
|
167
|
-
inner_statements << endless[i + 1]
|
168
|
-
i += 1
|
169
|
-
next
|
170
|
-
else
|
171
|
-
inner_statements << endless[i + 1]
|
172
|
-
i += 1
|
173
|
-
next
|
161
|
+
io = opts[:in][:io]
|
174
162
|
|
175
|
-
|
176
|
-
|
163
|
+
r = RubyLex.new
|
164
|
+
r.set_input io
|
165
|
+
r.skip_space = false
|
177
166
|
|
178
|
-
|
179
|
-
break
|
167
|
+
pure = opts[:out][:io]
|
180
168
|
|
181
|
-
|
182
|
-
|
183
|
-
|
169
|
+
indent = []
|
170
|
+
pass = []
|
171
|
+
bol = true
|
172
|
+
last = [0, 0]
|
173
|
+
bol_indent = 0
|
174
|
+
|
175
|
+
while t = r.token
|
184
176
|
|
185
|
-
|
186
|
-
i += 1
|
177
|
+
if bol && !(RubyToken::TkSPACE === t) && !(RubyToken::TkNL === t)
|
187
178
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
i -= comment_count
|
179
|
+
bol_indent = this_indent = t.char_no
|
180
|
+
while (indent.last && pass.last) && ((this_indent < indent.last) || (this_indent <= indent.last && !pass.last.include?(t.class)))
|
181
|
+
if RubyToken::TkEND === t && this_indent == indent.last
|
182
|
+
break
|
193
183
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
184
|
+
_indent = indent.pop
|
185
|
+
pass.pop
|
186
|
+
idt = []
|
187
|
+
loop do
|
188
|
+
pure.seek pure.pos - 1
|
189
|
+
if RUBY_VERSION < "1.9" # 1.8
|
190
|
+
c = pure.read(1)
|
191
|
+
else
|
192
|
+
c = pure.getc
|
193
|
+
break if pure.pos == 0 || !(["\n", ' '].include?(c))
|
194
|
+
pure.seek pure.pos - 1
|
195
|
+
idt.unshift c
|
196
|
+
if idt.first == "\n"
|
197
|
+
pure.write idt.shift
|
198
|
+
pure.write "#{' '*_indent}end\n"
|
199
|
+
pure.write idt.join
|
200
|
+
bol = false
|
201
|
+
|
202
|
+
case t
|
203
|
+
when RubyToken::TkNL
|
204
|
+
bol = true
|
205
|
+
when RubyToken::TkEND
|
206
|
+
indent.pop
|
207
|
+
pass.pop
|
208
|
+
if opts[:decompile]
|
209
|
+
last[0] += 3
|
210
|
+
last[1] += 3
|
211
|
+
next
|
212
|
+
when RubyToken::TkIF, RubyToken::TkUNLESS
|
213
|
+
pass << [RubyToken::TkELSE, RubyToken::TkELSIF]
|
214
|
+
indent << t.char_no
|
215
|
+
when RubyToken::TkFOR
|
216
|
+
pass << []
|
217
|
+
indent << t.char_no
|
218
|
+
when RubyToken::TkWHILE, RubyToken::TkUNTIL
|
219
|
+
pass << []
|
220
|
+
indent << t.char_no
|
221
|
+
when RubyToken::TkBEGIN
|
222
|
+
pass << [RubyToken::TkRESCUE, RubyToken::TkELSE, RubyToken::TkENSURE]
|
223
|
+
indent << t.char_no
|
224
|
+
when RubyToken::TkDEF
|
225
|
+
pass << [RubyToken::TkRESCUE, RubyToken::TkELSE, RubyToken::TkENSURE]
|
226
|
+
indent << t.char_no
|
227
|
+
when RubyToken::TkCLASS, RubyToken::TkMODULE
|
228
|
+
pass << []
|
229
|
+
indent << t.char_no
|
230
|
+
when RubyToken::TkCASE
|
231
|
+
pass << [RubyToken::TkWHEN, RubyToken::TkELSE]
|
232
|
+
indent << t.char_no
|
233
|
+
when RubyToken::TkDO
|
234
|
+
pass << []
|
235
|
+
indent << bol_indent
|
236
|
+
when RubyToken::TkSPACE
|
237
|
+
|
238
|
+
|
239
|
+
pos = io.pos
|
240
|
+
io.seek pos
|
241
|
+
|
242
|
+
pos = io.pos
|
243
|
+
|
244
|
+
if RUBY_VERSION < "1.9" # 1.8
|
245
|
+
io.seek t.seek
|
246
|
+
pure.write io.read(r.seek - t.seek)
|
247
|
+
else # 1.9
|
248
|
+
io.seek last[0]
|
249
|
+
(r.seek - last[1]).times do
|
250
|
+
pure.write io.getc
|
251
|
+
last = [io.pos, r.seek]
|
252
|
+
|
253
|
+
io.seek pos
|
254
|
+
|
255
|
+
until opts[:decompile] || (indent.empty? && pass.empty?)
|
256
|
+
_indent = indent.pop
|
257
|
+
pass.pop
|
258
|
+
pure.seek pure.pos - 1
|
259
|
+
if RUBY_VERSION < "1.9" # 1.8
|
260
|
+
c = pure.read 1
|
261
|
+
else
|
262
|
+
c = pure.getc
|
263
|
+
if c == "\n"
|
264
|
+
pure.write "#{' '*_indent}end"
|
199
265
|
else
|
200
|
-
#
|
201
|
-
if endless[i + 1] && endless[i + 1] =~ /^\s*end(?:\s|$)\s*$/
|
202
|
-
i += 1
|
266
|
+
pure.write "\n#{' '*_indent}end"
|
203
267
|
|
204
|
-
|
205
|
-
pure.
|
268
|
+
pure.seek 0
|
269
|
+
ret = pure.read.chomp
|
270
|
+
pure.seek 0
|
206
271
|
|
207
|
-
|
208
|
-
|
209
|
-
|
272
|
+
opts[:out][:ensure] && opts[:out][:ensure].call
|
273
|
+
opts[:in][:ensure] && opts[:in][:ensure].call
|
274
|
+
|
275
|
+
ret
|
210
276
|
|
211
277
|
if __FILE__ == $PROGRAM_NAME
|
212
278
|
require 'endlessruby/main'
|