t-ruby 0.0.7 → 0.0.34

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 054211b0b7c63b2f1b66b3cfed976385174c1b3f5904ea04357599b3c7440e8f
4
- data.tar.gz: 0aa86d48811cff1bc7d7652155055f5041c0bef8e372b9dcec4a06a716534799
3
+ metadata.gz: aaa0445c84cb0a6685e788645a19fee5d30d2f1e6f79052122fb16e8a3f08e91
4
+ data.tar.gz: 446845b5b1e470964f664d590197262f0e3555b82dd59f7b75a484324b99ec63
5
5
  SHA512:
6
- metadata.gz: 73ba77dc237a8455dd60b0c098de4372cd6e9f76e00619a54669af04fd46deca80c8c6fb1c3322114442ea38a471f18f722fc66018ad14cf31469ed153c11bc8
7
- data.tar.gz: 5b6c3d2d3a895f941949d79407cb2e0ce91c3d1b3a13d7e113cd02be1a8fbdd9a82fb86bf6ac1d99832d4e331861c8657b516836b334aa73c8175273835c6da5
6
+ metadata.gz: e422c5535edcb5085efd7018825c1675b06b3c2bb3657da1c6d9f6b07202233b53c03c145888fbdc221fc78df4873d18c2d0f4326d19ede16134eda409fb7418
7
+ data.tar.gz: 0d988eaa6c08a586af4c965447087467e500cc75de4d7bc879c239c3f6924caf504123fc3117ed9be4e676b0ae2715bdadf888218e8072702c1a66bbb329a288
data/README.md CHANGED
@@ -16,6 +16,10 @@
16
16
  <img src="https://img.shields.io/badge/coverage-90%25-brightgreen" alt="Coverage: 90%" />
17
17
  </p>
18
18
 
19
+ <p align="center">
20
+ <a href="https://type-ruby.github.io"><strong>🌐 Official Website</strong></a>
21
+ </p>
22
+
19
23
  <p align="center">
20
24
  <a href="#install">Install</a>
21
25
  &nbsp;&nbsp;•&nbsp;&nbsp;
@@ -106,7 +110,7 @@ end
106
110
  - Like TypeScript, types live inside your code.
107
111
  - Write `.trb`, and `trc` generates both `.rb` and `.rbs`.
108
112
 
109
- ```ruby
113
+ ```trb
110
114
  # greet.trb
111
115
  def greet(name: String): String
112
116
  "Hello, #{name}!"
@@ -150,7 +154,7 @@ trc --version
150
154
 
151
155
  ### 1. Write `.trb`
152
156
 
153
- ```ruby
157
+ ```trb
154
158
  # hello.trb
155
159
  def greet(name: String): String
156
160
  "Hello, #{name}!"
data/lib/t_ruby/cli.rb CHANGED
@@ -7,6 +7,9 @@ module TRuby
7
7
 
8
8
  Usage:
9
9
  trc <file.trb> Compile a .trb file to .rb
10
+ trc <file.rb> Copy .rb file to build/ and generate .rbs
11
+ trc --init Initialize a new t-ruby project
12
+ trc --config, -c <path> Use custom config file
10
13
  trc --watch, -w Watch input files and recompile on change
11
14
  trc --decl <file.trb> Generate .d.trb declaration file
12
15
  trc --lsp Start LSP server (for IDE integration)
@@ -15,8 +18,11 @@ module TRuby
15
18
 
16
19
  Examples:
17
20
  trc hello.trb Compile hello.trb to build/hello.rb
18
- trc -w Watch all .trb files in current directory
19
- trc -w src/ Watch all .trb files in src/ directory
21
+ trc utils.rb Copy utils.rb to build/ and generate utils.rbs
22
+ trc --init Create trbconfig.yml and src/, build/ directories
23
+ trc -c custom.yml file.trb Compile with custom config file
24
+ trc -w Watch all .trb and .rb files in current directory
25
+ trc -w src/ Watch all .trb and .rb files in src/ directory
20
26
  trc --watch hello.trb Watch specific file for changes
21
27
  trc --decl hello.trb Generate hello.d.trb declaration file
22
28
  trc --lsp Start language server for VS Code
@@ -41,6 +47,11 @@ module TRuby
41
47
  return
42
48
  end
43
49
 
50
+ if @args.include?("--init")
51
+ init_project
52
+ return
53
+ end
54
+
44
55
  if @args.include?("--lsp")
45
56
  start_lsp_server
46
57
  return
@@ -57,12 +68,95 @@ module TRuby
57
68
  return
58
69
  end
59
70
 
60
- input_file = @args.first
61
- compile(input_file)
71
+ # Extract config path if --config or -c flag is present
72
+ config_path = extract_config_path
73
+
74
+ # Get input file (first non-flag argument)
75
+ input_file = find_input_file
76
+ compile(input_file, config_path: config_path)
62
77
  end
63
78
 
64
79
  private
65
80
 
81
+ def init_project
82
+ config_file = "trbconfig.yml"
83
+ src_dir = "src"
84
+ build_dir = "build"
85
+
86
+ created = []
87
+ skipped = []
88
+
89
+ # Create trbconfig.yml with new schema
90
+ if File.exist?(config_file)
91
+ skipped << config_file
92
+ else
93
+ File.write(config_file, <<~YAML)
94
+ # T-Ruby configuration file
95
+ # See: https://type-ruby.github.io/docs/getting-started/project-configuration
96
+
97
+ source:
98
+ include:
99
+ - #{src_dir}
100
+ exclude: []
101
+ extensions:
102
+ - ".trb"
103
+ - ".rb"
104
+
105
+ output:
106
+ ruby_dir: #{build_dir}
107
+ # rbs_dir: sig # Optional: separate directory for .rbs files
108
+ preserve_structure: true
109
+ # clean_before_build: false
110
+
111
+ compiler:
112
+ strictness: standard # strict | standard | permissive
113
+ generate_rbs: true
114
+ target_ruby: "3.0"
115
+ # experimental: []
116
+ # checks:
117
+ # no_implicit_any: false
118
+ # no_unused_vars: false
119
+ # strict_nil: false
120
+
121
+ watch:
122
+ # paths: [] # Additional paths to watch
123
+ debounce: 100
124
+ # clear_screen: false
125
+ # on_success: "bundle exec rspec"
126
+ YAML
127
+ created << config_file
128
+ end
129
+
130
+ # Create src/ directory
131
+ if Dir.exist?(src_dir)
132
+ skipped << "#{src_dir}/"
133
+ else
134
+ Dir.mkdir(src_dir)
135
+ created << "#{src_dir}/"
136
+ end
137
+
138
+ # Create build/ directory
139
+ if Dir.exist?(build_dir)
140
+ skipped << "#{build_dir}/"
141
+ else
142
+ Dir.mkdir(build_dir)
143
+ created << "#{build_dir}/"
144
+ end
145
+
146
+ # Output results
147
+ if created.any?
148
+ puts "Created: #{created.join(', ')}"
149
+ end
150
+ if skipped.any?
151
+ puts "Skipped (already exists): #{skipped.join(', ')}"
152
+ end
153
+ if created.empty? && skipped.any?
154
+ puts "Project already initialized."
155
+ else
156
+ puts "t-ruby project initialized successfully!"
157
+ end
158
+ end
159
+
66
160
  def start_lsp_server
67
161
  server = LSPServer.new
68
162
  server.run
@@ -92,8 +186,8 @@ module TRuby
92
186
  exit 1
93
187
  end
94
188
 
95
- def compile(input_file)
96
- config = Config.new
189
+ def compile(input_file, config_path: nil)
190
+ config = Config.new(config_path)
97
191
  compiler = Compiler.new(config)
98
192
 
99
193
  output_path = compiler.compile(input_file)
@@ -102,5 +196,36 @@ module TRuby
102
196
  puts "Error: #{e.message}"
103
197
  exit 1
104
198
  end
199
+
200
+ # Extract config path from --config or -c flag
201
+ def extract_config_path
202
+ config_index = @args.index("--config") || @args.index("-c")
203
+ return nil unless config_index
204
+
205
+ @args[config_index + 1]
206
+ end
207
+
208
+ # Find the input file (first non-flag argument)
209
+ def find_input_file
210
+ skip_next = false
211
+ @args.each do |arg|
212
+ if skip_next
213
+ skip_next = false
214
+ next
215
+ end
216
+
217
+ # Skip known flags with arguments
218
+ if %w[--config -c --decl].include?(arg)
219
+ skip_next = true
220
+ next
221
+ end
222
+
223
+ # Skip flags without arguments
224
+ next if arg.start_with?("-")
225
+
226
+ return arg
227
+ end
228
+ nil
229
+ end
105
230
  end
106
231
  end
@@ -6,13 +6,13 @@ module TRuby
6
6
  class Compiler
7
7
  attr_reader :declaration_loader, :use_ir, :optimizer
8
8
 
9
- def initialize(config, use_ir: true, optimize: true)
10
- @config = config
9
+ def initialize(config = nil, use_ir: true, optimize: true)
10
+ @config = config || Config.new
11
11
  @use_ir = use_ir
12
12
  @optimize = optimize
13
13
  @declaration_loader = DeclarationLoader.new
14
14
  @optimizer = IR::Optimizer.new if use_ir && optimize
15
- setup_declaration_paths
15
+ setup_declaration_paths if @config
16
16
  end
17
17
 
18
18
  def compile(input_path)
@@ -20,8 +20,13 @@ module TRuby
20
20
  raise ArgumentError, "File not found: #{input_path}"
21
21
  end
22
22
 
23
+ # Handle .rb files separately
24
+ if input_path.end_with?(".rb")
25
+ return copy_ruby_file(input_path)
26
+ end
27
+
23
28
  unless input_path.end_with?(".trb")
24
- raise ArgumentError, "Expected .trb file, got: #{input_path}"
29
+ raise ArgumentError, "Expected .trb or .rb file, got: #{input_path}"
25
30
  end
26
31
 
27
32
  source = File.read(input_path)
@@ -42,22 +47,73 @@ module TRuby
42
47
  File.write(output_path, output)
43
48
 
44
49
  # Generate .rbs file if enabled in config
45
- if @config.emit["rbs"]
50
+ if @config.compiler["generate_rbs"]
51
+ rbs_dir = @config.rbs_dir
52
+ FileUtils.mkdir_p(rbs_dir)
46
53
  if @use_ir && parser.ir_program
47
- generate_rbs_from_ir(base_filename, out_dir, parser.ir_program)
54
+ generate_rbs_from_ir(base_filename, rbs_dir, parser.ir_program)
48
55
  else
49
- generate_rbs_file(base_filename, out_dir, parse_result)
56
+ generate_rbs_file(base_filename, rbs_dir, parse_result)
50
57
  end
51
58
  end
52
59
 
53
- # Generate .d.trb file if enabled in config
54
- if @config.emit["dtrb"]
60
+ # Generate .d.trb file if enabled in config (legacy support)
61
+ # TODO: Add compiler.generate_dtrb option in future
62
+ if @config.compiler.key?("generate_dtrb") && @config.compiler["generate_dtrb"]
55
63
  generate_dtrb_file(input_path, out_dir)
56
64
  end
57
65
 
58
66
  output_path
59
67
  end
60
68
 
69
+ # Compile T-Ruby source code from a string (useful for WASM/playground)
70
+ # @param source [String] T-Ruby source code
71
+ # @param options [Hash] Options for compilation
72
+ # @option options [Boolean] :rbs Whether to generate RBS output (default: true)
73
+ # @return [Hash] Result with :ruby, :rbs, :errors keys
74
+ def compile_string(source, options = {})
75
+ generate_rbs = options.fetch(:rbs, true)
76
+
77
+ parser = Parser.new(source, use_combinator: @use_ir)
78
+ parse_result = parser.parse
79
+
80
+ # Transform source to Ruby code
81
+ ruby_output = @use_ir ? transform_with_ir(source, parser) : transform_legacy(source, parse_result)
82
+
83
+ # Generate RBS if requested
84
+ rbs_output = ""
85
+ if generate_rbs
86
+ if @use_ir && parser.ir_program
87
+ generator = IR::RBSGenerator.new
88
+ rbs_output = generator.generate(parser.ir_program)
89
+ else
90
+ generator = RBSGenerator.new
91
+ rbs_output = generator.generate(
92
+ parse_result[:functions] || [],
93
+ parse_result[:type_aliases] || []
94
+ )
95
+ end
96
+ end
97
+
98
+ {
99
+ ruby: ruby_output,
100
+ rbs: rbs_output,
101
+ errors: []
102
+ }
103
+ rescue ParseError => e
104
+ {
105
+ ruby: "",
106
+ rbs: "",
107
+ errors: [e.message]
108
+ }
109
+ rescue StandardError => e
110
+ {
111
+ ruby: "",
112
+ rbs: "",
113
+ errors: ["Compilation error: #{e.message}"]
114
+ }
115
+ end
116
+
61
117
  # Compile to IR without generating output files
62
118
  def compile_to_ir(input_path)
63
119
  unless File.exist?(input_path)
@@ -166,6 +222,38 @@ module TRuby
166
222
  generator = DeclarationGenerator.new
167
223
  generator.generate_file(input_path, out_dir)
168
224
  end
225
+
226
+ # Copy .rb file to output directory and generate .rbs signature
227
+ def copy_ruby_file(input_path)
228
+ unless File.exist?(input_path)
229
+ raise ArgumentError, "File not found: #{input_path}"
230
+ end
231
+
232
+ out_dir = @config.out_dir
233
+ FileUtils.mkdir_p(out_dir)
234
+
235
+ base_filename = File.basename(input_path, ".rb")
236
+ output_path = File.join(out_dir, base_filename + ".rb")
237
+
238
+ # Copy the .rb file to output directory
239
+ FileUtils.cp(input_path, output_path)
240
+
241
+ # Generate .rbs file if enabled in config
242
+ if @config.compiler["generate_rbs"]
243
+ rbs_dir = @config.rbs_dir
244
+ FileUtils.mkdir_p(rbs_dir)
245
+ generate_rbs_from_ruby(base_filename, rbs_dir, input_path)
246
+ end
247
+
248
+ output_path
249
+ end
250
+
251
+ # Generate RBS from Ruby file using rbs prototype
252
+ def generate_rbs_from_ruby(base_filename, out_dir, input_path)
253
+ rbs_path = File.join(out_dir, base_filename + ".rbs")
254
+ result = `rbs prototype rb #{input_path} 2>/dev/null`
255
+ File.write(rbs_path, result) unless result.strip.empty?
256
+ end
169
257
  end
170
258
 
171
259
  # IR-aware code generator for source-preserving transformation