konpeito 0.2.4 → 0.3.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.
@@ -1,183 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "transport"
4
- require_relative "document_manager"
5
-
6
- module Konpeito
7
- module LSP
8
- # Main LSP server that handles client requests
9
- class Server
10
- attr_reader :transport, :document_manager
11
-
12
- def initialize(input: $stdin, output: $stdout)
13
- @transport = Transport.new(input: input, output: output)
14
- @document_manager = DocumentManager.new(@transport)
15
- @running = false
16
- @initialized = false
17
- end
18
-
19
- # Start the LSP server main loop
20
- def start
21
- @running = true
22
- while @running
23
- request = @transport.read
24
- break unless request
25
-
26
- response = handle_request(request)
27
- @transport.write(response) if response
28
- end
29
- end
30
-
31
- # Stop the server
32
- def stop
33
- @running = false
34
- end
35
-
36
- # Handle a single request (exposed for testing)
37
- # @param request [Hash] The LSP request
38
- # @return [Hash, nil] The response or nil for notifications
39
- def handle_request(request)
40
- method = request[:method]
41
- id = request[:id]
42
- params = request[:params] || {}
43
-
44
- result = case method
45
- when "initialize"
46
- handle_initialize(params)
47
- when "initialized"
48
- # Notification, no response needed
49
- nil
50
- when "shutdown"
51
- handle_shutdown
52
- when "exit"
53
- @running = false
54
- nil
55
- when "textDocument/didOpen"
56
- handle_did_open(params)
57
- when "textDocument/didChange"
58
- handle_did_change(params)
59
- when "textDocument/didClose"
60
- handle_did_close(params)
61
- when "textDocument/hover"
62
- handle_hover(params)
63
- when "textDocument/completion"
64
- handle_completion(params)
65
- when "textDocument/definition"
66
- handle_definition(params)
67
- when "textDocument/references"
68
- handle_references(params)
69
- when "textDocument/rename"
70
- handle_rename(params)
71
- when "textDocument/prepareRename"
72
- handle_prepare_rename(params)
73
- else
74
- # Unknown method
75
- if id
76
- { error: { code: -32601, message: "Method not found: #{method}" } }
77
- end
78
- end
79
-
80
- # Build response for requests (not notifications)
81
- if id && result != :notification
82
- { jsonrpc: "2.0", id: id, result: result }
83
- else
84
- nil
85
- end
86
- end
87
-
88
- private
89
-
90
- def handle_initialize(params)
91
- @initialized = true
92
-
93
- {
94
- capabilities: {
95
- textDocumentSync: {
96
- openClose: true,
97
- change: 1 # Full content sync
98
- },
99
- hoverProvider: true,
100
- completionProvider: {
101
- triggerCharacters: ["."],
102
- resolveProvider: false
103
- },
104
- definitionProvider: true,
105
- referencesProvider: true,
106
- renameProvider: {
107
- prepareProvider: true
108
- }
109
- },
110
- serverInfo: {
111
- name: "konpeito-lsp",
112
- version: Konpeito::VERSION
113
- }
114
- }
115
- end
116
-
117
- def handle_shutdown
118
- @initialized = false
119
- nil
120
- end
121
-
122
- def handle_did_open(params)
123
- uri = params.dig(:textDocument, :uri)
124
- text = params.dig(:textDocument, :text)
125
- @document_manager.open(uri, text)
126
- :notification
127
- end
128
-
129
- def handle_did_change(params)
130
- uri = params.dig(:textDocument, :uri)
131
- # We use full sync, so first contentChanges has full text
132
- changes = params[:contentChanges]
133
- text = changes&.first&.dig(:text)
134
- @document_manager.change(uri, text) if text
135
- :notification
136
- end
137
-
138
- def handle_did_close(params)
139
- uri = params.dig(:textDocument, :uri)
140
- @document_manager.close(uri)
141
- :notification
142
- end
143
-
144
- def handle_hover(params)
145
- uri = params.dig(:textDocument, :uri)
146
- position = params[:position]
147
- @document_manager.hover(uri, position)
148
- end
149
-
150
- def handle_completion(params)
151
- uri = params.dig(:textDocument, :uri)
152
- position = params[:position]
153
- @document_manager.completion(uri, position)
154
- end
155
-
156
- def handle_definition(params)
157
- uri = params.dig(:textDocument, :uri)
158
- position = params[:position]
159
- @document_manager.definition(uri, position)
160
- end
161
-
162
- def handle_references(params)
163
- uri = params.dig(:textDocument, :uri)
164
- position = params[:position]
165
- include_declaration = params.dig(:context, :includeDeclaration) != false
166
- @document_manager.references(uri, position, include_declaration: include_declaration)
167
- end
168
-
169
- def handle_rename(params)
170
- uri = params.dig(:textDocument, :uri)
171
- position = params[:position]
172
- new_name = params[:newName]
173
- @document_manager.rename(uri, position, new_name)
174
- end
175
-
176
- def handle_prepare_rename(params)
177
- uri = params.dig(:textDocument, :uri)
178
- position = params[:position]
179
- @document_manager.prepare_rename(uri, position)
180
- end
181
- end
182
- end
183
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "language_server-protocol"
4
-
5
- module Konpeito
6
- module LSP
7
- # Handles LSP JSON-RPC communication over stdio
8
- class Transport
9
- def initialize(input: $stdin, output: $stdout)
10
- @reader = LanguageServer::Protocol::Transport::Io::Reader.new(input)
11
- @writer = LanguageServer::Protocol::Transport::Io::Writer.new(output)
12
- end
13
-
14
- # Read next request/notification from client
15
- # @return [Hash, nil] The request object or nil if EOF
16
- def read
17
- @reader.read
18
- end
19
-
20
- # Write response to client
21
- # @param response [Hash] The response object
22
- def write(response)
23
- @writer.write(response)
24
- end
25
-
26
- # Send notification to client (no response expected)
27
- # @param method [String] The notification method
28
- # @param params [Hash] The notification parameters
29
- def notify(method, params)
30
- @writer.write({
31
- jsonrpc: "2.0",
32
- method: method,
33
- params: params
34
- })
35
- end
36
- end
37
- end
38
- end
data/test_native_array.rb DELETED
@@ -1,172 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Simple test for NativeArray
4
-
5
- $LOAD_PATH.unshift File.expand_path("lib", __dir__)
6
- require "konpeito"
7
-
8
- source = <<~RUBY
9
- def test_alloc(n)
10
- arr = NativeArray.new(n)
11
- arr.length
12
- end
13
-
14
- def test_set(n)
15
- arr = NativeArray.new(n)
16
- arr[0] = 3.14
17
- arr[0]
18
- end
19
-
20
- def test_fill(n)
21
- arr = NativeArray.new(n)
22
-
23
- # Just fill array
24
- i = 0
25
- while i < n
26
- arr[i] = i * 1.5
27
- i = i + 1
28
- end
29
-
30
- arr[0]
31
- end
32
-
33
- def test_read_sum(n)
34
- arr = NativeArray.new(n)
35
-
36
- # Fill with simple values
37
- i = 0
38
- while i < n
39
- arr[i] = 1.0
40
- i = i + 1
41
- end
42
-
43
- # Try to read all values
44
- total = arr[0]
45
- total = total + arr[1]
46
- total = total + arr[2]
47
-
48
- total
49
- end
50
- RUBY
51
-
52
- rbs = <<~RBS
53
- class NativeArray[T]
54
- def self.new: (Integer size) -> NativeArray[Float]
55
- def []: (Integer index) -> Float
56
- def []=: (Integer index, Float value) -> Float
57
- def length: () -> Integer
58
- end
59
-
60
- class Object
61
- def test_alloc: (Integer n) -> Integer
62
- def test_set: (Integer n) -> Float
63
- def test_fill: (Integer n) -> Float
64
- def test_read_sum: (Integer n) -> Float
65
- end
66
- RBS
67
-
68
- require "tempfile"
69
- require "fileutils"
70
-
71
- tmp_dir = "tmp"
72
- FileUtils.mkdir_p(tmp_dir)
73
-
74
- source_path = File.join(tmp_dir, "test_native.rb")
75
- rbs_path = File.join(tmp_dir, "test_native.rbs")
76
- output_path = File.join(tmp_dir, "test_native.bundle")
77
-
78
- File.write(source_path, source)
79
- File.write(rbs_path, rbs)
80
-
81
- compiler = Konpeito::Compiler.new(
82
- source_file: source_path,
83
- output_file: output_path,
84
- format: :cruby_ext,
85
- rbs_paths: [rbs_path],
86
- optimize: false, # Disable optimization for debugging
87
- verbose: true
88
- )
89
-
90
- # Patch to capture LLVM IR
91
- module Konpeito
92
- module Codegen
93
- class LLVMGenerator
94
- def to_ir
95
- @mod.to_s
96
- end
97
- end
98
- end
99
- end
100
-
101
- puts "Compiling..."
102
-
103
- # Manual compilation steps to capture IR
104
- ast = compiler.send(:parse)
105
- typed_ast = compiler.send(:type_check_ast, ast)
106
- hir = compiler.send(:generate_hir, typed_ast)
107
-
108
- puts "\n=== HIR Functions ==="
109
- hir.functions.each do |func|
110
- puts "Function: #{func.name}"
111
- func.body.each do |block|
112
- puts " Block: #{block.label}"
113
- block.instructions.each do |inst|
114
- puts " #{inst.class.name.split('::').last}: #{inst.result_var}"
115
- end
116
- puts " Terminator: #{block.terminator.class.name.split('::').last}" if block.terminator
117
- end
118
- end
119
-
120
- llvm_gen = Konpeito::Codegen::LLVMGenerator.new(
121
- module_name: "test_native",
122
- monomorphizer: nil
123
- )
124
- llvm_gen.generate(hir)
125
-
126
- puts "\n=== LLVM IR ==="
127
- puts llvm_gen.to_ir
128
-
129
- puts "\n=== Compiling to native ==="
130
- backend = Konpeito::Codegen::CRubyBackend.new(
131
- llvm_gen,
132
- output_file: output_path,
133
- module_name: "test_native"
134
- )
135
- backend.generate
136
- puts "Generated: #{output_path}"
137
-
138
- puts "\n=== Testing ==="
139
- require File.expand_path(output_path)
140
-
141
- puts "\nTest 1: test_alloc"
142
- result = Object.new.send(:test_alloc, 10)
143
- puts "test_alloc(10) = #{result}"
144
- puts "Expected: 10"
145
- puts result == 10 ? "PASS" : "FAIL"
146
-
147
- puts "\nTest 2: test_set"
148
- result = Object.new.send(:test_set, 5)
149
- expected = 3.14
150
- puts "test_set(5) = #{result}"
151
- puts "Expected: #{expected}"
152
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"
153
-
154
- puts "\nTest 3: test_fill"
155
- result = Object.new.send(:test_fill, 5)
156
- # arr[0] = 0 * 1.5 = 0.0
157
- expected = 0.0
158
- puts "test_fill(5) = #{result}"
159
- puts "Expected: #{expected}"
160
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"
161
-
162
- puts "\nTest 4: test_read_sum"
163
- result = Object.new.send(:test_read_sum, 5)
164
- # 1.0 + 1.0 + 1.0 = 3.0
165
- expected = 3.0
166
- puts "test_read_sum(5) = #{result}"
167
- puts "Expected: #{expected}"
168
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"
169
- result = Object.new.send(:test_alloc, 10)
170
- puts "test_alloc(10) = #{result}"
171
- puts "Expected: 10"
172
- puts result == 10 ? "PASS" : "FAIL"
@@ -1,197 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Test for NativeArray[NativeClass] - array of structs
4
-
5
- $LOAD_PATH.unshift File.expand_path("lib", __dir__)
6
- require "konpeito"
7
-
8
- source = <<~RUBY
9
- def test_create_and_access(n)
10
- particles = NativeArray.new(n)
11
-
12
- # Set first particle
13
- particles[0].x = 1.0
14
- particles[0].y = 2.0
15
-
16
- # Set second particle
17
- particles[1].x = 3.0
18
- particles[1].y = 4.0
19
-
20
- # Return sum of all coordinates
21
- particles[0].x + particles[0].y + particles[1].x + particles[1].y
22
- end
23
-
24
- def test_loop_access(n)
25
- particles = NativeArray.new(n)
26
-
27
- # Initialize particles
28
- i = 0
29
- while i < n
30
- particles[i].x = i * 1.0
31
- particles[i].y = i * 2.0
32
- i = i + 1
33
- end
34
-
35
- # Sum all x coordinates
36
- total = 0.0
37
- i = 0
38
- while i < n
39
- total = total + particles[i].x
40
- i = i + 1
41
- end
42
-
43
- total
44
- end
45
-
46
- def test_distance_sum(n)
47
- particles = NativeArray.new(n)
48
-
49
- # Place particles in a line
50
- i = 0
51
- while i < n
52
- particles[i].x = i * 10.0
53
- particles[i].y = 0.0
54
- i = i + 1
55
- end
56
-
57
- # Sum distances between consecutive particles
58
- total = 0.0
59
- i = 0
60
- while i < n - 1
61
- dx = particles[i + 1].x - particles[i].x
62
- dy = particles[i + 1].y - particles[i].y
63
- total = total + dx * dx + dy * dy
64
- i = i + 1
65
- end
66
-
67
- total
68
- end
69
- RUBY
70
-
71
- rbs = <<~RBS
72
- # @native
73
- class Particle
74
- @x: Float
75
- @y: Float
76
-
77
- def self.new: () -> Particle
78
- def x: () -> Float
79
- def x=: (Float value) -> Float
80
- def y: () -> Float
81
- def y=: (Float value) -> Float
82
- end
83
-
84
- class Object
85
- def test_create_and_access: (Integer n) -> Float
86
- def test_loop_access: (Integer n) -> Float
87
- def test_distance_sum: (Integer n) -> Float
88
- end
89
- RBS
90
-
91
- require "tempfile"
92
- require "fileutils"
93
-
94
- tmp_dir = "tmp"
95
- FileUtils.mkdir_p(tmp_dir)
96
-
97
- source_path = File.join(tmp_dir, "test_native_array_class.rb")
98
- rbs_path = File.join(tmp_dir, "test_native_array_class.rbs")
99
- output_path = File.join(tmp_dir, "test_native_array_class.bundle")
100
-
101
- File.write(source_path, source)
102
- File.write(rbs_path, rbs)
103
-
104
- compiler = Konpeito::Compiler.new(
105
- source_file: source_path,
106
- output_file: output_path,
107
- format: :cruby_ext,
108
- rbs_paths: [rbs_path],
109
- optimize: false,
110
- verbose: true
111
- )
112
-
113
- # Patch to capture LLVM IR
114
- module Konpeito
115
- module Codegen
116
- class LLVMGenerator
117
- def to_ir
118
- @mod.to_s
119
- end
120
- end
121
- end
122
- end
123
-
124
- puts "Compiling..."
125
-
126
- # Manual compilation steps to capture IR
127
- ast = compiler.send(:parse)
128
- typed_ast = compiler.send(:type_check_ast, ast)
129
- hir = compiler.send(:generate_hir, typed_ast)
130
-
131
- puts "\n=== HIR Functions ==="
132
- hir.functions.each do |func|
133
- puts "Function: #{func.name}"
134
- func.body.each do |block|
135
- puts " Block: #{block.label}"
136
- block.instructions.each do |inst|
137
- case inst
138
- when Konpeito::HIR::NativeArrayAlloc
139
- puts " NativeArrayAlloc: #{inst.result_var} (element: #{inst.element_type})"
140
- when Konpeito::HIR::NativeArrayGet
141
- puts " NativeArrayGet: #{inst.result_var} (element: #{inst.element_type})"
142
- when Konpeito::HIR::NativeFieldGet
143
- puts " NativeFieldGet: #{inst.result_var} (field: #{inst.field_name})"
144
- when Konpeito::HIR::NativeFieldSet
145
- puts " NativeFieldSet: (field: #{inst.field_name})"
146
- else
147
- puts " #{inst.class.name.split('::').last}: #{inst.result_var}"
148
- end
149
- end
150
- puts " Terminator: #{block.terminator.class.name.split('::').last}" if block.terminator
151
- end
152
- end
153
-
154
- llvm_gen = Konpeito::Codegen::LLVMGenerator.new(
155
- module_name: "test_native_array_class",
156
- monomorphizer: nil
157
- )
158
- llvm_gen.generate(hir)
159
-
160
- puts "\n=== LLVM IR ==="
161
- puts llvm_gen.to_ir
162
-
163
- puts "\n=== Compiling to native ==="
164
- backend = Konpeito::Codegen::CRubyBackend.new(
165
- llvm_gen,
166
- output_file: output_path,
167
- module_name: "test_native_array_class"
168
- )
169
- backend.generate
170
- puts "Generated: #{output_path}"
171
-
172
- puts "\n=== Testing ==="
173
- require File.expand_path(output_path)
174
-
175
- puts "\nTest 1: test_create_and_access"
176
- result = Object.new.send(:test_create_and_access, 5)
177
- expected = 1.0 + 2.0 + 3.0 + 4.0 # 10.0
178
- puts "test_create_and_access(5) = #{result}"
179
- puts "Expected: #{expected}"
180
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"
181
-
182
- puts "\nTest 2: test_loop_access"
183
- result = Object.new.send(:test_loop_access, 5)
184
- # Sum of 0*1.0 + 1*1.0 + 2*1.0 + 3*1.0 + 4*1.0 = 0+1+2+3+4 = 10.0
185
- expected = 10.0
186
- puts "test_loop_access(5) = #{result}"
187
- puts "Expected: #{expected}"
188
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"
189
-
190
- puts "\nTest 3: test_distance_sum"
191
- result = Object.new.send(:test_distance_sum, 5)
192
- # Distance squared between consecutive particles at x=0,10,20,30,40
193
- # Each distance squared = 10*10 = 100, 4 pairs = 400
194
- expected = 400.0
195
- puts "test_distance_sum(5) = #{result}"
196
- puts "Expected: #{expected}"
197
- puts (result - expected).abs < 0.001 ? "PASS" : "FAIL"