t-ruby 0.0.42 → 0.0.43

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/t_ruby/ast_type_inferrer.rb +2 -0
  3. data/lib/t_ruby/cache.rb +40 -10
  4. data/lib/t_ruby/cli.rb +13 -8
  5. data/lib/t_ruby/compiler.rb +168 -0
  6. data/lib/t_ruby/diagnostic.rb +115 -0
  7. data/lib/t_ruby/diagnostic_formatter.rb +162 -0
  8. data/lib/t_ruby/error_handler.rb +201 -35
  9. data/lib/t_ruby/error_reporter.rb +57 -0
  10. data/lib/t_ruby/ir.rb +39 -1
  11. data/lib/t_ruby/lsp_server.rb +40 -97
  12. data/lib/t_ruby/parser.rb +18 -4
  13. data/lib/t_ruby/parser_combinator/combinators/alternative.rb +20 -0
  14. data/lib/t_ruby/parser_combinator/combinators/chain_left.rb +34 -0
  15. data/lib/t_ruby/parser_combinator/combinators/choice.rb +29 -0
  16. data/lib/t_ruby/parser_combinator/combinators/flat_map.rb +21 -0
  17. data/lib/t_ruby/parser_combinator/combinators/label.rb +22 -0
  18. data/lib/t_ruby/parser_combinator/combinators/lookahead.rb +21 -0
  19. data/lib/t_ruby/parser_combinator/combinators/many.rb +29 -0
  20. data/lib/t_ruby/parser_combinator/combinators/many1.rb +32 -0
  21. data/lib/t_ruby/parser_combinator/combinators/map.rb +17 -0
  22. data/lib/t_ruby/parser_combinator/combinators/not_followed_by.rb +21 -0
  23. data/lib/t_ruby/parser_combinator/combinators/optional.rb +21 -0
  24. data/lib/t_ruby/parser_combinator/combinators/sep_by.rb +34 -0
  25. data/lib/t_ruby/parser_combinator/combinators/sep_by1.rb +34 -0
  26. data/lib/t_ruby/parser_combinator/combinators/sequence.rb +23 -0
  27. data/lib/t_ruby/parser_combinator/combinators/skip_right.rb +23 -0
  28. data/lib/t_ruby/parser_combinator/declaration_parser.rb +147 -0
  29. data/lib/t_ruby/parser_combinator/dsl.rb +115 -0
  30. data/lib/t_ruby/parser_combinator/parse_error.rb +48 -0
  31. data/lib/t_ruby/parser_combinator/parse_result.rb +46 -0
  32. data/lib/t_ruby/parser_combinator/parser.rb +84 -0
  33. data/lib/t_ruby/parser_combinator/primitives/end_of_input.rb +16 -0
  34. data/lib/t_ruby/parser_combinator/primitives/fail.rb +16 -0
  35. data/lib/t_ruby/parser_combinator/primitives/lazy.rb +18 -0
  36. data/lib/t_ruby/parser_combinator/primitives/literal.rb +21 -0
  37. data/lib/t_ruby/parser_combinator/primitives/pure.rb +16 -0
  38. data/lib/t_ruby/parser_combinator/primitives/regex.rb +25 -0
  39. data/lib/t_ruby/parser_combinator/primitives/satisfy.rb +21 -0
  40. data/lib/t_ruby/parser_combinator/token/expression_parser.rb +541 -0
  41. data/lib/t_ruby/parser_combinator/token/statement_parser.rb +644 -0
  42. data/lib/t_ruby/parser_combinator/token/token_alternative.rb +20 -0
  43. data/lib/t_ruby/parser_combinator/token/token_body_parser.rb +54 -0
  44. data/lib/t_ruby/parser_combinator/token/token_declaration_parser.rb +920 -0
  45. data/lib/t_ruby/parser_combinator/token/token_dsl.rb +16 -0
  46. data/lib/t_ruby/parser_combinator/token/token_label.rb +22 -0
  47. data/lib/t_ruby/parser_combinator/token/token_many.rb +29 -0
  48. data/lib/t_ruby/parser_combinator/token/token_many1.rb +32 -0
  49. data/lib/t_ruby/parser_combinator/token/token_map.rb +17 -0
  50. data/lib/t_ruby/parser_combinator/token/token_matcher.rb +29 -0
  51. data/lib/t_ruby/parser_combinator/token/token_optional.rb +21 -0
  52. data/lib/t_ruby/parser_combinator/token/token_parse_result.rb +40 -0
  53. data/lib/t_ruby/parser_combinator/token/token_parser.rb +62 -0
  54. data/lib/t_ruby/parser_combinator/token/token_sep_by.rb +34 -0
  55. data/lib/t_ruby/parser_combinator/token/token_sep_by1.rb +34 -0
  56. data/lib/t_ruby/parser_combinator/token/token_sequence.rb +23 -0
  57. data/lib/t_ruby/parser_combinator/token/token_skip_right.rb +23 -0
  58. data/lib/t_ruby/parser_combinator/type_parser.rb +103 -0
  59. data/lib/t_ruby/parser_combinator.rb +64 -936
  60. data/lib/t_ruby/scanner.rb +883 -0
  61. data/lib/t_ruby/version.rb +1 -1
  62. data/lib/t_ruby/watcher.rb +67 -75
  63. data/lib/t_ruby.rb +15 -1
  64. metadata +51 -2
  65. data/lib/t_ruby/body_parser.rb +0 -561
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TRuby
4
- VERSION = "0.0.42"
4
+ VERSION = "0.0.43"
5
5
  end
@@ -33,6 +33,7 @@ module TRuby
33
33
  @error_count = 0
34
34
  @file_count = 0
35
35
  @use_colors = $stdout.tty?
36
+ @file_diagnostics = {} # Cache diagnostics per file for incremental updates
36
37
 
37
38
  # Enhanced features
38
39
  @incremental = incremental
@@ -138,48 +139,27 @@ module TRuby
138
139
  def compile_all
139
140
  @error_count = 0
140
141
  @file_count = 0
141
- errors = []
142
+ @file_diagnostics = {} # Reset diagnostics cache on full compile
142
143
 
143
144
  trb_files = find_trb_files
144
145
  rb_files = find_rb_files
145
146
  all_files = trb_files + rb_files
146
147
  @file_count = all_files.size
147
148
 
148
- if @incremental && @cross_file_check
149
- # Use enhanced incremental compiler with cross-file checking
150
- result = @incremental_compiler.compile_all_with_checking(trb_files)
151
- errors = result[:errors].map { |e| format_error(e[:file], e[:error] || e[:message]) }
152
- @error_count = errors.size
153
- @stats[:total_compilations] += trb_files.size
154
-
155
- # Also compile .rb files
156
- rb_files.each do |file|
157
- result = compile_file(file)
158
- errors.concat(result[:errors]) if result[:errors].any?
159
- end
160
- elsif @parallel && all_files.size > 1
161
- # Parallel compilation
162
- results = @parallel_processor.process_files(all_files) do |file|
163
- compile_file(file)
164
- end
165
- results.each do |result|
166
- errors.concat(result[:errors]) if result[:errors]&.any?
167
- end
168
- else
169
- # Sequential compilation
170
- all_files.each do |file|
171
- result = compile_file(file)
172
- errors.concat(result[:errors]) if result[:errors].any?
173
- end
149
+ # Use unified compile_with_diagnostics for all files
150
+ # Note: compile_file increments @stats[:total_compilations] internally
151
+ all_files.each do |file|
152
+ result = compile_file(file)
153
+ # Cache diagnostics per file
154
+ @file_diagnostics[file] = result[:diagnostics] || []
174
155
  end
175
156
 
176
- print_errors(errors)
157
+ all_diagnostics = @file_diagnostics.values.flatten
158
+ print_errors(all_diagnostics)
177
159
  print_summary
178
160
  end
179
161
 
180
162
  def compile_files_incremental(files)
181
- @error_count = 0
182
- errors = []
183
163
  compiled_count = 0
184
164
 
185
165
  if @incremental
@@ -187,7 +167,8 @@ module TRuby
187
167
  if @incremental_compiler.needs_compile?(file)
188
168
  @stats[:total_compilations] += 1
189
169
  result = compile_file_with_ir(file)
190
- errors.concat(result[:errors]) if result[:errors].any?
170
+ # Update cached diagnostics for this file
171
+ @file_diagnostics[file] = result[:diagnostics] || []
191
172
  compiled_count += 1
192
173
  else
193
174
  @stats[:incremental_hits] += 1
@@ -199,56 +180,59 @@ module TRuby
199
180
  if @cross_file_check && @incremental_compiler.cross_file_checker
200
181
  check_result = @incremental_compiler.cross_file_checker.check_all
201
182
  check_result[:errors].each do |e|
202
- errors << format_error(e[:file], e[:message])
183
+ # Add cross-file errors (these are not file-specific)
184
+ @file_diagnostics[:cross_file] ||= []
185
+ @file_diagnostics[:cross_file] << create_diagnostic_from_cross_file_error(e)
203
186
  end
204
187
  end
205
188
  else
206
189
  files.each do |file|
207
190
  result = compile_file(file)
208
- errors.concat(result[:errors]) if result[:errors].any?
191
+ # Update cached diagnostics for this file
192
+ @file_diagnostics[file] = result[:diagnostics] || []
209
193
  compiled_count += 1
210
194
  end
211
195
  end
212
196
 
197
+ # Collect all diagnostics from cache (includes unchanged files' errors)
198
+ all_diagnostics = @file_diagnostics.values.flatten
199
+
200
+ # Update error count from all cached diagnostics
201
+ @error_count = all_diagnostics.size
202
+
213
203
  @file_count = compiled_count
214
- print_errors(errors)
204
+ print_errors(all_diagnostics)
215
205
  print_summary
216
206
  print_watching_message
217
207
  end
218
208
 
219
209
  def compile_file_with_ir(file)
220
- result = { file: file, errors: [], success: false }
210
+ # Use unified compile_with_diagnostics from Compiler (same as compile_file)
211
+ # This ensures incremental compile returns the same diagnostics as full compile
212
+ compile_result = @compiler.compile_with_diagnostics(file)
221
213
 
222
- begin
223
- @incremental_compiler.compile_with_ir(file)
224
- result[:success] = true
225
- rescue ArgumentError => e
226
- @error_count += 1
227
- result[:errors] << format_error(file, e.message)
228
- rescue StandardError => e
229
- @error_count += 1
230
- result[:errors] << format_error(file, e.message)
231
- end
214
+ # Update incremental compiler's file hash to track changes
215
+ @incremental_compiler&.update_file_hash(file)
232
216
 
233
- result
217
+ {
218
+ file: file,
219
+ diagnostics: compile_result[:diagnostics],
220
+ success: compile_result[:success],
221
+ }
234
222
  end
235
223
 
236
224
  def compile_file(file)
237
- result = { file: file, errors: [], success: false }
225
+ # Use unified compile_with_diagnostics from Compiler
226
+ compile_result = @compiler.compile_with_diagnostics(file)
238
227
 
239
- begin
240
- @compiler.compile(file)
241
- result[:success] = true
242
- @stats[:total_compilations] += 1
243
- rescue ArgumentError => e
244
- @error_count += 1
245
- result[:errors] << format_error(file, e.message)
246
- rescue StandardError => e
247
- @error_count += 1
248
- result[:errors] << format_error(file, e.message)
249
- end
228
+ @error_count += compile_result[:diagnostics].size
229
+ @stats[:total_compilations] += 1
250
230
 
251
- result
231
+ {
232
+ file: file,
233
+ diagnostics: compile_result[:diagnostics],
234
+ success: compile_result[:success],
235
+ }
252
236
  end
253
237
 
254
238
  def find_trb_files
@@ -284,9 +268,15 @@ module TRuby
284
268
  files.uniq
285
269
  end
286
270
 
287
- def format_error(file, message)
288
- # Parse error message for line/column info if available
289
- # Format: file:line:col - error TRB0001: message
271
+ # Create a Diagnostic for cross-file check errors
272
+ def create_diagnostic_from_cross_file_error(error)
273
+ file = error[:file]
274
+ source = File.exist?(file) ? File.read(file) : nil
275
+ create_generic_diagnostic(file, error[:message], source)
276
+ end
277
+
278
+ # Create a generic Diagnostic for standard errors
279
+ def create_generic_diagnostic(file, message, source = nil)
290
280
  line = 1
291
281
  col = 1
292
282
 
@@ -295,23 +285,25 @@ module TRuby
295
285
  line = ::Regexp.last_match(1).to_i
296
286
  end
297
287
 
298
- {
299
- file: file,
300
- line: line,
301
- col: col,
288
+ source_line = source&.split("\n")&.at(line - 1)
289
+
290
+ Diagnostic.new(
291
+ code: "TR0001",
302
292
  message: message,
303
- }
293
+ file: relative_path(file),
294
+ line: line,
295
+ column: col,
296
+ source_line: source_line
297
+ )
304
298
  end
305
299
 
306
- def print_errors(errors)
307
- errors.each do |error|
300
+ def print_errors(diagnostics)
301
+ return if diagnostics.empty?
302
+
303
+ formatter = DiagnosticFormatter.new(use_colors: @use_colors)
304
+ diagnostics.each do |diagnostic|
308
305
  puts
309
- # TypeScript-style error format: file:line:col - error TSXXXX: message
310
- location = "#{colorize(:cyan,
311
- relative_path(error[:file]))}:#{colorize(:yellow,
312
- error[:line])}:#{colorize(:yellow,
313
- error[:col])}"
314
- puts "#{location} - #{colorize(:red, "error")} #{colorize(:gray, "TRB0001")}: #{error[:message]}"
306
+ puts formatter.format(diagnostic)
315
307
  end
316
308
  end
317
309
 
data/lib/t_ruby.rb CHANGED
@@ -10,18 +10,21 @@ require_relative "t_ruby/config"
10
10
  require_relative "t_ruby/string_utils"
11
11
  require_relative "t_ruby/ir"
12
12
  require_relative "t_ruby/parser_combinator"
13
+ require_relative "t_ruby/scanner"
13
14
  require_relative "t_ruby/smt_solver"
14
15
 
15
16
  # Basic components
16
17
  require_relative "t_ruby/type_alias_registry"
17
18
  require_relative "t_ruby/heredoc_detector"
18
- require_relative "t_ruby/body_parser"
19
19
  require_relative "t_ruby/parser"
20
20
  require_relative "t_ruby/union_type_parser"
21
21
  require_relative "t_ruby/generic_type_parser"
22
22
  require_relative "t_ruby/intersection_type_parser"
23
23
  require_relative "t_ruby/type_erasure"
24
24
  require_relative "t_ruby/error_handler"
25
+ require_relative "t_ruby/diagnostic"
26
+ require_relative "t_ruby/diagnostic_formatter"
27
+ require_relative "t_ruby/error_reporter"
25
28
  require_relative "t_ruby/declaration_generator"
26
29
  require_relative "t_ruby/compiler"
27
30
  require_relative "t_ruby/lsp_server"
@@ -51,4 +54,15 @@ require_relative "t_ruby/docs_example_verifier"
51
54
  require_relative "t_ruby/docs_badge_generator"
52
55
 
53
56
  module TRuby
57
+ # Parse error for T-Ruby source code
58
+ class ParseError < StandardError
59
+ attr_reader :line, :column, :source
60
+
61
+ def initialize(message, line: nil, column: nil, source: nil)
62
+ @line = line
63
+ @column = column
64
+ @source = source
65
+ super(message)
66
+ end
67
+ end
54
68
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: t-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.42
4
+ version: 0.0.43
5
5
  platform: ruby
6
6
  authors:
7
7
  - Y. Fred Kim
@@ -38,7 +38,6 @@ files:
38
38
  - lib/t_ruby.rb
39
39
  - lib/t_ruby/ast_type_inferrer.rb
40
40
  - lib/t_ruby/benchmark.rb
41
- - lib/t_ruby/body_parser.rb
42
41
  - lib/t_ruby/bundler_integration.rb
43
42
  - lib/t_ruby/cache.rb
44
43
  - lib/t_ruby/cli.rb
@@ -47,11 +46,14 @@ files:
47
46
  - lib/t_ruby/config.rb
48
47
  - lib/t_ruby/constraint_checker.rb
49
48
  - lib/t_ruby/declaration_generator.rb
49
+ - lib/t_ruby/diagnostic.rb
50
+ - lib/t_ruby/diagnostic_formatter.rb
50
51
  - lib/t_ruby/doc_generator.rb
51
52
  - lib/t_ruby/docs_badge_generator.rb
52
53
  - lib/t_ruby/docs_example_extractor.rb
53
54
  - lib/t_ruby/docs_example_verifier.rb
54
55
  - lib/t_ruby/error_handler.rb
56
+ - lib/t_ruby/error_reporter.rb
55
57
  - lib/t_ruby/generic_type_parser.rb
56
58
  - lib/t_ruby/heredoc_detector.rb
57
59
  - lib/t_ruby/intersection_type_parser.rb
@@ -60,8 +62,55 @@ files:
60
62
  - lib/t_ruby/package_manager.rb
61
63
  - lib/t_ruby/parser.rb
62
64
  - lib/t_ruby/parser_combinator.rb
65
+ - lib/t_ruby/parser_combinator/combinators/alternative.rb
66
+ - lib/t_ruby/parser_combinator/combinators/chain_left.rb
67
+ - lib/t_ruby/parser_combinator/combinators/choice.rb
68
+ - lib/t_ruby/parser_combinator/combinators/flat_map.rb
69
+ - lib/t_ruby/parser_combinator/combinators/label.rb
70
+ - lib/t_ruby/parser_combinator/combinators/lookahead.rb
71
+ - lib/t_ruby/parser_combinator/combinators/many.rb
72
+ - lib/t_ruby/parser_combinator/combinators/many1.rb
73
+ - lib/t_ruby/parser_combinator/combinators/map.rb
74
+ - lib/t_ruby/parser_combinator/combinators/not_followed_by.rb
75
+ - lib/t_ruby/parser_combinator/combinators/optional.rb
76
+ - lib/t_ruby/parser_combinator/combinators/sep_by.rb
77
+ - lib/t_ruby/parser_combinator/combinators/sep_by1.rb
78
+ - lib/t_ruby/parser_combinator/combinators/sequence.rb
79
+ - lib/t_ruby/parser_combinator/combinators/skip_right.rb
80
+ - lib/t_ruby/parser_combinator/declaration_parser.rb
81
+ - lib/t_ruby/parser_combinator/dsl.rb
82
+ - lib/t_ruby/parser_combinator/parse_error.rb
83
+ - lib/t_ruby/parser_combinator/parse_result.rb
84
+ - lib/t_ruby/parser_combinator/parser.rb
85
+ - lib/t_ruby/parser_combinator/primitives/end_of_input.rb
86
+ - lib/t_ruby/parser_combinator/primitives/fail.rb
87
+ - lib/t_ruby/parser_combinator/primitives/lazy.rb
88
+ - lib/t_ruby/parser_combinator/primitives/literal.rb
89
+ - lib/t_ruby/parser_combinator/primitives/pure.rb
90
+ - lib/t_ruby/parser_combinator/primitives/regex.rb
91
+ - lib/t_ruby/parser_combinator/primitives/satisfy.rb
92
+ - lib/t_ruby/parser_combinator/token/expression_parser.rb
93
+ - lib/t_ruby/parser_combinator/token/statement_parser.rb
94
+ - lib/t_ruby/parser_combinator/token/token_alternative.rb
95
+ - lib/t_ruby/parser_combinator/token/token_body_parser.rb
96
+ - lib/t_ruby/parser_combinator/token/token_declaration_parser.rb
97
+ - lib/t_ruby/parser_combinator/token/token_dsl.rb
98
+ - lib/t_ruby/parser_combinator/token/token_label.rb
99
+ - lib/t_ruby/parser_combinator/token/token_many.rb
100
+ - lib/t_ruby/parser_combinator/token/token_many1.rb
101
+ - lib/t_ruby/parser_combinator/token/token_map.rb
102
+ - lib/t_ruby/parser_combinator/token/token_matcher.rb
103
+ - lib/t_ruby/parser_combinator/token/token_optional.rb
104
+ - lib/t_ruby/parser_combinator/token/token_parse_result.rb
105
+ - lib/t_ruby/parser_combinator/token/token_parser.rb
106
+ - lib/t_ruby/parser_combinator/token/token_sep_by.rb
107
+ - lib/t_ruby/parser_combinator/token/token_sep_by1.rb
108
+ - lib/t_ruby/parser_combinator/token/token_sequence.rb
109
+ - lib/t_ruby/parser_combinator/token/token_skip_right.rb
110
+ - lib/t_ruby/parser_combinator/type_parser.rb
63
111
  - lib/t_ruby/ruby_version.rb
64
112
  - lib/t_ruby/runtime_validator.rb
113
+ - lib/t_ruby/scanner.rb
65
114
  - lib/t_ruby/smt_solver.rb
66
115
  - lib/t_ruby/string_utils.rb
67
116
  - lib/t_ruby/type_alias_registry.rb