gloss 0.0.4 → 0.1.2
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.
- checksums.yaml +4 -4
- data/.gitattributes +3 -0
- data/.github/workflows/{crystal.yml → crystal_specs.yml} +1 -1
- data/.github/workflows/{ruby.yml → ruby_specs.yml} +2 -2
- data/.gloss.yml +1 -0
- data/.rspec +1 -0
- data/Gemfile.lock +9 -11
- data/README.md +35 -5
- data/Rakefile +1 -1
- data/exe/gloss +13 -2
- data/ext/gloss/Makefile +8 -19
- data/ext/gloss/spec/parser_spec.cr +83 -83
- data/ext/gloss/src/cr_ast.cr +63 -77
- data/ext/gloss/src/gloss.cr +1 -2
- data/ext/gloss/src/rb_ast.cr +40 -38
- data/lib/gloss.rb +15 -7
- data/lib/gloss/cli.rb +75 -32
- data/lib/gloss/config.rb +10 -3
- data/lib/gloss/errors.rb +1 -1
- data/lib/gloss/initializer.rb +6 -5
- data/lib/gloss/logger.rb +29 -0
- data/lib/gloss/parser.rb +17 -2
- data/lib/gloss/prog_loader.rb +141 -0
- data/lib/gloss/scope.rb +1 -1
- data/lib/gloss/source.rb +1 -1
- data/lib/gloss/type_checker.rb +80 -32
- data/lib/gloss/utils.rb +44 -0
- data/lib/gloss/version.rb +5 -5
- data/lib/gloss/{builder.rb → visitor.rb} +125 -74
- data/lib/gloss/watcher.rb +47 -11
- data/lib/gloss/writer.rb +22 -11
- data/sig/core.rbs +2 -0
- data/sig/fast_blank.rbs +4 -0
- data/sig/{gloss.rbs → gls.rbs} +0 -0
- data/sig/optparse.rbs +6 -0
- data/sig/rubygems.rbs +9 -0
- data/sig/yaml.rbs +3 -0
- data/src/exe/gloss +19 -0
- data/src/lib/gloss.gl +26 -0
- data/src/lib/gloss/cli.gl +53 -24
- data/src/lib/gloss/config.gl +9 -3
- data/src/lib/gloss/initializer.gl +4 -6
- data/src/lib/gloss/logger.gl +21 -0
- data/src/lib/gloss/parser.gl +17 -5
- data/src/lib/gloss/prog_loader.gl +133 -0
- data/src/lib/gloss/scope.gl +0 -2
- data/src/lib/gloss/type_checker.gl +85 -39
- data/src/lib/gloss/utils.gl +38 -0
- data/src/lib/gloss/version.gl +1 -1
- data/src/lib/gloss/{builder.gl → visitor.gl} +123 -68
- data/src/lib/gloss/watcher.gl +44 -10
- data/src/lib/gloss/writer.gl +16 -14
- metadata +23 -8
@@ -0,0 +1,38 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
module Gloss
|
4
|
+
module Utils
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def absolute_path(path)
|
8
|
+
pn = Pathname.new(path)
|
9
|
+
if pn.absolute?
|
10
|
+
pn.to_s
|
11
|
+
else
|
12
|
+
ap = File.absolute_path path
|
13
|
+
if File.exist? ap
|
14
|
+
ap
|
15
|
+
else
|
16
|
+
throw :error, "File path #{path} does not exist (also looked for #{ap})"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def gem_path_for(gem_name)
|
22
|
+
Gem.ui.instance_variable_set :"@outs", StringIO.new
|
23
|
+
Gem::GemRunner.new.run(["which", gem_name])
|
24
|
+
Gem.ui.outs.string
|
25
|
+
rescue SystemExit => e
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_file_header(str)
|
30
|
+
"#{Visitor::FILE_HEADER}\n\n#{str}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def src_path_to_output_path(src_path : String) : String
|
34
|
+
src_path.sub("#{Config.src_dir}/", "")
|
35
|
+
.sub(/\.gl$/, ".rb")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/src/lib/gloss/version.gl
CHANGED
@@ -1,27 +1,26 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module Gloss
|
4
|
-
class
|
2
|
+
class Visitor
|
3
|
+
FILE_HEADER = <<~RUBY
|
4
|
+
#{"# frozen_string_literal: true\n" if Config.frozen_string_literals}
|
5
|
+
##### This file was generated by Gloss; any changes made here will be overwritten.
|
6
|
+
##### See #{Config.src_dir}/ to make changes
|
7
|
+
RUBY
|
8
|
+
|
5
9
|
attr_reader :tree
|
6
10
|
|
7
|
-
def initialize(tree_hash, type_checker = nil)
|
11
|
+
def initialize(tree_hash, type_checker = nil, @on_new_file_referenced = nil)
|
8
12
|
@indent_level = 0
|
9
13
|
@inside_macro = false
|
10
14
|
@eval_vars = false
|
11
15
|
@current_scope = nil
|
12
16
|
@tree = tree_hash
|
13
17
|
@type_checker = type_checker
|
18
|
+
@after_module_function = false
|
14
19
|
end
|
15
20
|
|
16
21
|
def run
|
17
22
|
rb_output = visit_node(@tree)
|
18
|
-
|
19
|
-
#{"# frozen_string_literal: true\n" if Config.frozen_string_literals}
|
20
|
-
##### This file was generated by Gloss; any changes made here will be overwritten.
|
21
|
-
##### See #{Config.src_dir}/ to make changes
|
22
|
-
|
23
|
-
#{rb_output}
|
24
|
-
RUBY
|
23
|
+
Utils.with_file_header(rb_output)
|
25
24
|
end
|
26
25
|
|
27
26
|
# type node = Hash[Symbol, String | Array[String | node] | Hash[Symbol, node]] | true | false
|
@@ -33,18 +32,31 @@ module Gloss
|
|
33
32
|
class_name = visit_node(node[:name])
|
34
33
|
current_namespace = @current_scope ? @current_scope.name.to_namespace : RBS::Namespace.root
|
35
34
|
superclass_type = nil
|
36
|
-
superclass_output =
|
35
|
+
superclass_output = ""
|
37
36
|
if node[:superclass]
|
38
37
|
@eval_vars = true
|
39
38
|
superclass_output = visit_node(node[:superclass])
|
40
39
|
@eval_vars = false
|
41
|
-
|
40
|
+
args = Array.new
|
42
41
|
if node.dig(:superclass, :type) == "Generic"
|
43
|
-
superclass_output = superclass_output[/^[^\[]+/]
|
42
|
+
superclass_output = superclass_output[/^[^\[]+/] || superclass_output
|
43
|
+
args = node.dig(:superclass, :args).map { |n| RBS::Parser.parse_type(visit_node(n)) }
|
44
44
|
end
|
45
|
+
|
46
|
+
class_name_index = superclass_output.index(/[^(?:::)]+\z/) || 0
|
47
|
+
namespace = superclass_output[0, class_name_index]
|
48
|
+
superclass_name = superclass_output[/[^(?:::)]+\z/] || superclass_output
|
49
|
+
superclass_type = RBS::AST::Declarations::Class::Super.new(
|
50
|
+
name: RBS::TypeName.new(
|
51
|
+
namespace: method(:Namespace).call(namespace),
|
52
|
+
name: superclass_name.to_sym,
|
53
|
+
),
|
54
|
+
args: args,
|
55
|
+
location: build_location(node),
|
56
|
+
)
|
45
57
|
end
|
46
58
|
|
47
|
-
src.write_ln "class #{class_name}#{" < #{superclass_output}"
|
59
|
+
src.write_ln "class #{class_name}#{" < #{superclass_output}" unless superclass_output.blank?}"
|
48
60
|
|
49
61
|
class_type = RBS::AST::Declarations::Class.new(
|
50
62
|
name: RBS::TypeName.new(
|
@@ -55,7 +67,7 @@ module Gloss
|
|
55
67
|
super_class: superclass_type,
|
56
68
|
members: Array.new, # TODO
|
57
69
|
annotations: Array.new, # TODO
|
58
|
-
location: node
|
70
|
+
location: build_location(node),
|
59
71
|
comment: node[:comment]
|
60
72
|
)
|
61
73
|
old_parent_scope = @current_scope
|
@@ -69,10 +81,12 @@ module Gloss
|
|
69
81
|
|
70
82
|
@current_scope.members << class_type if @current_scope
|
71
83
|
|
72
|
-
if @type_checker
|
73
|
-
@type_checker.top_level_decls
|
84
|
+
if @type_checker && !@current_scope
|
85
|
+
@type_checker.top_level_decls.add(class_type)
|
74
86
|
end
|
75
87
|
when "ModuleNode"
|
88
|
+
existing_module_function_state = @after_module_function.dup
|
89
|
+
@after_module_function = false
|
76
90
|
module_name = visit_node node[:name]
|
77
91
|
src.write_ln "module #{module_name}"
|
78
92
|
|
@@ -87,7 +101,7 @@ module Gloss
|
|
87
101
|
self_types: Array.new, # TODO
|
88
102
|
members: Array.new, # TODO
|
89
103
|
annotations: Array.new, # TODO
|
90
|
-
location: node
|
104
|
+
location: build_location(node),
|
91
105
|
comment: node[:comment]
|
92
106
|
)
|
93
107
|
old_parent_scope = @current_scope
|
@@ -99,13 +113,15 @@ module Gloss
|
|
99
113
|
|
100
114
|
@current_scope.members << module_type if @current_scope
|
101
115
|
|
102
|
-
if @type_checker
|
103
|
-
@type_checker.top_level_decls
|
116
|
+
if @type_checker && !@current_scope
|
117
|
+
@type_checker.top_level_decls.add(module_type)
|
104
118
|
end
|
105
119
|
src.write_ln "end"
|
120
|
+
@after_module_function = existing_module_function_state
|
106
121
|
when "DefNode"
|
107
122
|
args = render_args(node)
|
108
|
-
|
123
|
+
receiver = node[:receiver] ? visit_node(node[:receiver]) : nil
|
124
|
+
src.write_ln "def #{"#{receiver}." if receiver}#{node[:name]}#{args[:representation]}"
|
109
125
|
|
110
126
|
return_type = if node[:return_type]
|
111
127
|
RBS::Types::ClassInstance.new(
|
@@ -114,44 +130,25 @@ module Gloss
|
|
114
130
|
namespace: RBS::Namespace.root
|
115
131
|
),
|
116
132
|
args: EMPTY_ARRAY, # TODO
|
117
|
-
location: node
|
133
|
+
location: build_location(node)
|
118
134
|
)
|
119
135
|
else
|
120
136
|
RBS::Types::Bases::Any.new(
|
121
|
-
location: node
|
137
|
+
location: build_location(node)
|
122
138
|
)
|
123
139
|
end
|
124
140
|
|
125
|
-
rp : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| !a[:value] }
|
126
|
-
op : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| a[:value] }
|
127
|
-
|
128
141
|
method_types = [
|
129
142
|
RBS::MethodType.new(
|
130
143
|
type_params: EMPTY_ARRAY, # TODO
|
131
144
|
type: RBS::Types::Function.new(
|
132
|
-
required_positionals:
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end,
|
140
|
-
optional_positionals: op.map do |a|
|
141
|
-
RBS::Types::Function::Param.new(
|
142
|
-
name: visit_node(a).to_sym,
|
143
|
-
type: RBS::Types::Bases::Any.new(location: a[:location])
|
144
|
-
)
|
145
|
-
end,
|
146
|
-
rest_positionals: (rpa = node[:rest_p_args]) ? RBS::Types::Function::Param.new(name: visit_node(rpa).to_sym, type: RBS::Types::Bases::Any.new(location: node[:location])) : nil,
|
147
|
-
trailing_positionals: EMPTY_ARRAY, # TODO
|
148
|
-
required_keywords: node[:req_kw_args] || EMPTY_HASH,
|
149
|
-
optional_keywords: node[:opt_kw_args] || EMPTY_HASH,
|
150
|
-
rest_keywords: node[:rest_kw_args] ?
|
151
|
-
RBS::Types::Function::Param.new(
|
152
|
-
name: visit_node(node[:rest_kw_args]).to_sym,
|
153
|
-
type: RBS::Types::Bases::Any.new(location: node[:location])
|
154
|
-
) : nil,
|
145
|
+
required_positionals: args.dig(:types, :required_positionals),
|
146
|
+
optional_positionals: args.dig(:types, :optional_positionals),
|
147
|
+
rest_positionals: args.dig(:types, :rest_positionals),
|
148
|
+
trailing_positionals: args.dig(:types, :trailing_positionals),
|
149
|
+
required_keywords: args.dig(:types, :required_keywords),
|
150
|
+
optional_keywords: args.dig(:types, :optional_keywords),
|
151
|
+
rest_keywords: args.dig(:types, :rest_keywords),
|
155
152
|
return_type: return_type
|
156
153
|
),
|
157
154
|
block: node[:yield_arg_count] ?
|
@@ -164,19 +161,19 @@ module Gloss
|
|
164
161
|
required_keywords: Hash.new,
|
165
162
|
optional_keywords: Hash.new,
|
166
163
|
rest_keywords: nil,
|
167
|
-
return_type: RBS::Types::Bases::Any.new(location: node
|
164
|
+
return_type: RBS::Types::Bases::Any.new(location: build_location(node))
|
168
165
|
),
|
169
166
|
required: !!(node[:block_arg] || node[:yield_arg_count])
|
170
167
|
) : nil,
|
171
|
-
location: node
|
168
|
+
location: build_location(node)
|
172
169
|
)
|
173
170
|
]
|
174
171
|
method_definition = RBS::AST::Members::MethodDefinition.new(
|
175
172
|
name: node[:name].to_sym,
|
176
|
-
kind: :instance,
|
173
|
+
kind: @after_module_function ? :singleton_instance : receiver ? :singleton : :instance,
|
177
174
|
types: method_types,
|
178
175
|
annotations: EMPTY_ARRAY, # TODO
|
179
|
-
location: node
|
176
|
+
location: build_location(node),
|
180
177
|
comment: node[:comment],
|
181
178
|
overload: false
|
182
179
|
)
|
@@ -212,12 +209,19 @@ module Gloss
|
|
212
209
|
else
|
213
210
|
nil
|
214
211
|
end
|
215
|
-
|
212
|
+
name = node[:name]
|
213
|
+
call = "#{obj}#{name}#{opening_delimiter}#{args}#{")" if has_parens}#{block}"
|
214
|
+
case name
|
215
|
+
when "require_relative"
|
216
|
+
@on_new_file_referenced.call(name, true) if @on_new_file_referenced
|
217
|
+
when "module_function"
|
218
|
+
@after_module_function = true
|
219
|
+
end
|
216
220
|
src.write_ln(call)
|
217
221
|
|
218
222
|
when "Block"
|
219
|
-
|
220
|
-
src.write "{
|
223
|
+
args = render_args node
|
224
|
+
src.write "{ #{args[:representation].gsub(/(\A\(|\)\z)/,'|')}\n"
|
221
225
|
|
222
226
|
indented(src) { src.write visit_node(node[:body]) }
|
223
227
|
|
@@ -226,9 +230,10 @@ module Gloss
|
|
226
230
|
when "RangeLiteral"
|
227
231
|
dots = node[:exclusive] ? "..." : ".."
|
228
232
|
|
229
|
-
# parentheses help the compatibility with precendence of operators in some situations
|
233
|
+
# parentheses around the whole thing help the compatibility with precendence of operators in some situations
|
230
234
|
# eg. (1..3).cover? 2 vs. 1..3.cover? 2
|
231
|
-
|
235
|
+
# parentheses around either number help with things like arithemtic ((x-1)..(y+5))
|
236
|
+
src.write "(", "(", visit_node(node[:from]), ")", dots, "(", visit_node(node[:to]), ")", ")"
|
232
237
|
|
233
238
|
when "LiteralNode"
|
234
239
|
|
@@ -256,9 +261,10 @@ module Gloss
|
|
256
261
|
src.write node[:value]
|
257
262
|
|
258
263
|
when "Require"
|
264
|
+
path = node[:value]
|
265
|
+
src.write_ln %(require "#{path}")
|
259
266
|
|
260
|
-
|
261
|
-
|
267
|
+
@on_new_file_referenced.call(path, false) if @on_new_file_referenced
|
262
268
|
when "Assign", "OpAssign"
|
263
269
|
|
264
270
|
src.write_ln "#{visit_node(node[:target])} #{node[:op]}= #{visit_node(node[:value]).strip}"
|
@@ -307,12 +313,12 @@ module Gloss
|
|
307
313
|
contents = node[:elements].map do |k, v|
|
308
314
|
key = case k
|
309
315
|
when String
|
310
|
-
k.to_sym
|
316
|
+
k.to_sym.inspect
|
311
317
|
else
|
312
318
|
visit_node k
|
313
319
|
end
|
314
320
|
value = visit_node v
|
315
|
-
"#{key
|
321
|
+
"#{key} => #{value}"
|
316
322
|
end
|
317
323
|
|
318
324
|
src.write "{#{contents.join(",\n")}}"
|
@@ -397,7 +403,8 @@ module Gloss
|
|
397
403
|
src.write "return#{val}"
|
398
404
|
when "TypeDeclaration"
|
399
405
|
src.write_ln "# @type var #{visit_node(node[:var])}: #{visit_node(node[:declared_type])}"
|
400
|
-
|
406
|
+
value = node[:value] ? " = #{visit_node node[:value]}" : nil
|
407
|
+
src.write_ln "#{visit_node(node[:var])}#{value}"
|
401
408
|
when "ExceptionHandler"
|
402
409
|
src.write_ln "begin"
|
403
410
|
indented src do
|
@@ -431,7 +438,7 @@ module Gloss
|
|
431
438
|
name: method(:TypeName).call(name),
|
432
439
|
args: Array.new,
|
433
440
|
annotations: Array.new,
|
434
|
-
location: node
|
441
|
+
location: build_location(node),
|
435
442
|
comment: node[:comment]
|
436
443
|
)
|
437
444
|
if @current_scope
|
@@ -447,7 +454,7 @@ module Gloss
|
|
447
454
|
name: method(:TypeName).call(name),
|
448
455
|
args: Array.new,
|
449
456
|
annotations: Array.new,
|
450
|
-
location: node
|
457
|
+
location: build_location(node),
|
451
458
|
comment: node[:comment]
|
452
459
|
)
|
453
460
|
if @current_scope
|
@@ -466,6 +473,9 @@ module Gloss
|
|
466
473
|
types.map { |t| visit_node(t) }.join(" | ")
|
467
474
|
end
|
468
475
|
src.write output
|
476
|
+
when "Next"
|
477
|
+
val = " #{node[:value]}" if node[:value]
|
478
|
+
src.write "next#{val}"
|
469
479
|
when "EmptyNode"
|
470
480
|
# pass
|
471
481
|
else
|
@@ -497,7 +507,8 @@ module Gloss
|
|
497
507
|
src.decrement_indent
|
498
508
|
end
|
499
509
|
|
500
|
-
|
510
|
+
# TODO: allow NamedTuple as return type
|
511
|
+
private def render_args(node)# : { representation: String, types: Hash[Symbol, Any] }
|
501
512
|
rp : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| !a[:value] }
|
502
513
|
op : Array[Hash[Symbol, Any]] = node.fetch(:positional_args) { EMPTY_ARRAY }.filter { |a| a[:value] }
|
503
514
|
rkw : Hash[Symbol, Any] = node.fetch(:req_kw_args) { EMPTY_HASH }
|
@@ -514,7 +525,51 @@ module Gloss
|
|
514
525
|
rest_p ? "*#{rest_p}" : "",
|
515
526
|
rest_kw ? "**#{visit_node(rest_kw)}" : ""
|
516
527
|
].reject(&:empty?).flatten.join(", ")
|
517
|
-
"(#{contents})"
|
528
|
+
representation = "(#{contents})"
|
529
|
+
rp_args = rp.map do |a|
|
530
|
+
RBS::Types::Function::Param.new(
|
531
|
+
name: visit_node(a).to_sym,
|
532
|
+
type: RBS::Types::Bases::Any.new(
|
533
|
+
location: build_location(a)
|
534
|
+
)
|
535
|
+
)
|
536
|
+
end
|
537
|
+
op_args = op.map do |a|
|
538
|
+
RBS::Types::Function::Param.new(
|
539
|
+
name: visit_node(a).to_sym,
|
540
|
+
type: RBS::Types::Bases::Any.new(location: build_location(a))
|
541
|
+
)
|
542
|
+
end
|
543
|
+
rpa = rest_p ? RBS::Types::Function::Param.new(
|
544
|
+
name: rest_p.to_sym,
|
545
|
+
type: RBS::Types::Bases::Any.new(location: build_location(node))
|
546
|
+
) : nil
|
547
|
+
{
|
548
|
+
representation: representation,
|
549
|
+
types: {
|
550
|
+
required_positionals: rp_args,
|
551
|
+
optional_positionals: op_args,
|
552
|
+
rest_positionals: rpa,
|
553
|
+
trailing_positionals: EMPTY_ARRAY, # TODO
|
554
|
+
required_keywords: node[:req_kw_args] || EMPTY_HASH,
|
555
|
+
optional_keywords: node[:opt_kw_args] || EMPTY_HASH,
|
556
|
+
rest_keywords: node[:rest_kw_args] ?
|
557
|
+
RBS::Types::Function::Param.new(
|
558
|
+
name: visit_node(node[:rest_kw_args]).to_sym,
|
559
|
+
type: RBS::Types::Bases::Any.new(location: build_location(node))
|
560
|
+
) : nil
|
561
|
+
}
|
562
|
+
}
|
563
|
+
end
|
564
|
+
|
565
|
+
def build_location(node)
|
566
|
+
return nil unless node[:location]
|
567
|
+
|
568
|
+
# RBS::Location.new(
|
569
|
+
# buffer: RBS::Buffer.new(@file_path, @file_content),
|
570
|
+
# start_pos: node[:location][:start],
|
571
|
+
# end_pos: node[:location][:end]
|
572
|
+
# )
|
518
573
|
end
|
519
574
|
end
|
520
575
|
end
|
data/src/lib/gloss/watcher.gl
CHANGED
@@ -1,30 +1,64 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
require "listen"
|
4
2
|
|
5
3
|
module Gloss
|
6
4
|
class Watcher
|
7
|
-
def initialize
|
8
|
-
@paths
|
5
|
+
def initialize(@paths : Array[String])
|
6
|
+
if @paths.empty?
|
7
|
+
@paths = [File.join(Dir.pwd, Config.src_dir)]
|
8
|
+
# either any filepath with .gl extension, or executable with extension
|
9
|
+
@only = /(?:(\.gl|(?:(?<=\/)[^\.\/]+))\z|\A[^\.\/]+\z)/
|
10
|
+
else
|
11
|
+
file_names = Array.new
|
12
|
+
paths = Array.new
|
13
|
+
@paths.each do |pa|
|
14
|
+
pn = Pathname.new(pa)
|
15
|
+
paths << pn.parent.to_s
|
16
|
+
file_names << (pn.file? ? pn.basename.to_s : pa)
|
17
|
+
end
|
18
|
+
@paths = paths.uniq
|
19
|
+
@only = /#{Regexp.union(file_names)}/
|
20
|
+
end
|
9
21
|
end
|
10
22
|
|
11
23
|
def watch
|
12
|
-
|
13
|
-
listener = Listen.to(
|
24
|
+
Gloss.logger.info "Now listening for changes in #{@paths.join(', ')}"
|
25
|
+
listener = Listen.to(
|
26
|
+
*@paths,
|
27
|
+
latency: 2,
|
28
|
+
only: @only
|
29
|
+
) do |modified, added, removed|
|
14
30
|
(modified + added).each do |f|
|
31
|
+
Gloss.logger.info "Rewriting #{f}"
|
15
32
|
content = File.read(f)
|
16
|
-
|
33
|
+
err = catch :error do
|
34
|
+
Writer.new(
|
35
|
+
Visitor.new(
|
36
|
+
Parser.new(
|
37
|
+
content
|
38
|
+
).run
|
39
|
+
).run, f
|
40
|
+
).run
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
if err
|
44
|
+
Gloss.logger.error err
|
45
|
+
else
|
46
|
+
Gloss.logger.info "Done"
|
47
|
+
end
|
17
48
|
end
|
18
49
|
removed.each do |f|
|
19
50
|
out_path = Utils.src_path_to_output_path(f)
|
51
|
+
Gloss.logger.info "Removing #{out_path}"
|
20
52
|
File.delete out_path if File.exist? out_path
|
53
|
+
|
54
|
+
Gloss.logger.info "Done"
|
21
55
|
end
|
22
56
|
end
|
23
|
-
listener.start
|
24
57
|
begin
|
25
|
-
|
58
|
+
listener.start
|
59
|
+
sleep
|
26
60
|
rescue Interrupt
|
27
|
-
|
61
|
+
Gloss.logger.info "Interrupt signal received, shutting down"
|
28
62
|
exit 0
|
29
63
|
end
|
30
64
|
end
|