rlsl 0.1.1 → 1.0.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.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -1
  3. data/README.md +2 -0
  4. data/lib/rlsl/base_translator/call_parser.rb +68 -0
  5. data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
  6. data/lib/rlsl/base_translator/code_scanner.rb +102 -0
  7. data/lib/rlsl/base_translator.rb +159 -63
  8. data/lib/rlsl/code_generator/math_prelude.rb +79 -0
  9. data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +97 -0
  10. data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
  11. data/lib/rlsl/code_generator/template_context.rb +41 -0
  12. data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
  13. data/lib/rlsl/code_generator.rb +26 -201
  14. data/lib/rlsl/compiled_shader.rb +4 -12
  15. data/lib/rlsl/function_context.rb +31 -14
  16. data/lib/rlsl/glsl/translator.rb +19 -38
  17. data/lib/rlsl/msl/shader.rb +8 -38
  18. data/lib/rlsl/msl/translator.rb +19 -36
  19. data/lib/rlsl/msl/uniform_buffer_packer.rb +68 -0
  20. data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +96 -0
  21. data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +79 -0
  22. data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +168 -0
  23. data/lib/rlsl/prism/ast_visitor/scope_context.rb +44 -0
  24. data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
  25. data/lib/rlsl/prism/ast_visitor.rb +54 -298
  26. data/lib/rlsl/prism/builtins/function_registry.rb +114 -0
  27. data/lib/rlsl/prism/builtins/operator_rules.rb +99 -0
  28. data/lib/rlsl/prism/builtins/swizzle_rules.rb +38 -0
  29. data/lib/rlsl/prism/builtins.rb +31 -148
  30. data/lib/rlsl/prism/compilation_unit.rb +7 -0
  31. data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +83 -0
  32. data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +104 -0
  33. data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +92 -0
  34. data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +89 -0
  35. data/lib/rlsl/prism/emitters/base_emitter.rb +68 -423
  36. data/lib/rlsl/prism/emitters/c_emitter.rb +78 -121
  37. data/lib/rlsl/prism/emitters/glsl_emitter.rb +30 -65
  38. data/lib/rlsl/prism/emitters/msl_emitter.rb +35 -62
  39. data/lib/rlsl/prism/emitters/target_emitter.rb +77 -0
  40. data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
  41. data/lib/rlsl/prism/emitters/wgsl_emitter.rb +65 -61
  42. data/lib/rlsl/prism/ir/control_flow.rb +83 -0
  43. data/lib/rlsl/prism/ir/definitions.rb +67 -0
  44. data/lib/rlsl/prism/ir/expressions.rb +197 -0
  45. data/lib/rlsl/prism/ir/node.rb +21 -0
  46. data/lib/rlsl/prism/ir/nodes.rb +4 -371
  47. data/lib/rlsl/prism/ir/traversal.rb +62 -0
  48. data/lib/rlsl/prism/source_extractor/block_locator.rb +52 -0
  49. data/lib/rlsl/prism/source_extractor.rb +14 -133
  50. data/lib/rlsl/prism/source_unit/parser.rb +78 -0
  51. data/lib/rlsl/prism/source_unit.rb +42 -0
  52. data/lib/rlsl/prism/target_capability_validator.rb +85 -0
  53. data/lib/rlsl/prism/transpiler.rb +63 -60
  54. data/lib/rlsl/prism/type_inference/call_type_resolver.rb +35 -0
  55. data/lib/rlsl/prism/type_inference/call_validator.rb +71 -0
  56. data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +80 -0
  57. data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +66 -0
  58. data/lib/rlsl/prism/type_inference/definition_inferer.rb +41 -0
  59. data/lib/rlsl/prism/type_inference/expression_inferer.rb +92 -0
  60. data/lib/rlsl/prism/type_inference/field_type_resolver.rb +17 -0
  61. data/lib/rlsl/prism/type_inference/inferer_registry.rb +38 -0
  62. data/lib/rlsl/prism/type_inference/scope_stack.rb +47 -0
  63. data/lib/rlsl/prism/type_inference/type_environment.rb +112 -0
  64. data/lib/rlsl/prism/type_inference/type_shapes.rb +33 -0
  65. data/lib/rlsl/prism/type_inference.rb +114 -248
  66. data/lib/rlsl/runtime_shader.rb +47 -0
  67. data/lib/rlsl/shader_builder/build_service.rb +77 -0
  68. data/lib/rlsl/shader_builder/native_extension_compiler.rb +71 -0
  69. data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
  70. data/lib/rlsl/shader_builder/source_resolver.rb +91 -0
  71. data/lib/rlsl/shader_builder.rb +22 -113
  72. data/lib/rlsl/types/catalog.rb +47 -0
  73. data/lib/rlsl/types/target_resolver.rb +15 -0
  74. data/lib/rlsl/types/type_spec.rb +167 -0
  75. data/lib/rlsl/types/value_normalizer.rb +81 -0
  76. data/lib/rlsl/types.rb +11 -29
  77. data/lib/rlsl/uniform_context.rb +6 -12
  78. data/lib/rlsl/version.rb +1 -1
  79. data/lib/rlsl/wgsl/translator.rb +23 -39
  80. data/lib/rlsl.rb +14 -12
  81. metadata +55 -2
@@ -1,373 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module RLSL
4
- module Prism
5
- module IR
6
- class Node
7
- attr_accessor :type
8
-
9
- def accept(visitor)
10
- raise NotImplementedError
11
- end
12
- end
13
-
14
- class Block < Node
15
- attr_reader :statements
16
-
17
- def initialize(statements = [])
18
- super()
19
- @statements = statements
20
- end
21
-
22
- def accept(visitor)
23
- visitor.visit_block(self)
24
- end
25
- end
26
-
27
- class VarDecl < Node
28
- attr_reader :name, :initializer
29
-
30
- def initialize(name, initializer, type = nil)
31
- super()
32
- @name = name
33
- @initializer = initializer
34
- @type = type
35
- end
36
-
37
- def accept(visitor)
38
- visitor.visit_var_decl(self)
39
- end
40
- end
41
-
42
- class VarRef < Node
43
- attr_reader :name
44
-
45
- def initialize(name, type = nil)
46
- super()
47
- @name = name
48
- @type = type
49
- end
50
-
51
- def accept(visitor)
52
- visitor.visit_var_ref(self)
53
- end
54
- end
55
-
56
- class Literal < Node
57
- attr_reader :value
58
-
59
- def initialize(value, type = nil)
60
- super()
61
- @value = value
62
- @type = type || (value.is_a?(Float) ? :float : :int)
63
- end
64
-
65
- def accept(visitor)
66
- visitor.visit_literal(self)
67
- end
68
- end
69
-
70
- class BoolLiteral < Node
71
- attr_reader :value
72
-
73
- def initialize(value)
74
- super()
75
- @value = value
76
- @type = :bool
77
- end
78
-
79
- def accept(visitor)
80
- visitor.visit_bool_literal(self)
81
- end
82
- end
83
-
84
- class BinaryOp < Node
85
- attr_reader :operator, :left, :right
86
-
87
- def initialize(operator, left, right, type = nil)
88
- super()
89
- @operator = operator
90
- @left = left
91
- @right = right
92
- @type = type
93
- end
94
-
95
- def accept(visitor)
96
- visitor.visit_binary_op(self)
97
- end
98
- end
99
-
100
- class UnaryOp < Node
101
- attr_reader :operator, :operand
102
-
103
- def initialize(operator, operand, type = nil)
104
- super()
105
- @operator = operator
106
- @operand = operand
107
- @type = type
108
- end
109
-
110
- def accept(visitor)
111
- visitor.visit_unary_op(self)
112
- end
113
- end
114
-
115
- class FuncCall < Node
116
- attr_reader :name, :args, :receiver
117
-
118
- def initialize(name, args = [], receiver = nil, type = nil)
119
- super()
120
- @name = name
121
- @args = args
122
- @receiver = receiver
123
- @type = type
124
- end
125
-
126
- def accept(visitor)
127
- visitor.visit_func_call(self)
128
- end
129
- end
130
-
131
- class FieldAccess < Node
132
- attr_reader :receiver, :field
133
-
134
- def initialize(receiver, field, type = nil)
135
- super()
136
- @receiver = receiver
137
- @field = field
138
- @type = type
139
- end
140
-
141
- def accept(visitor)
142
- visitor.visit_field_access(self)
143
- end
144
- end
145
-
146
- class Swizzle < Node
147
- attr_reader :receiver, :components
148
-
149
- def initialize(receiver, components, type = nil)
150
- super()
151
- @receiver = receiver
152
- @components = components
153
- @type = type
154
- end
155
-
156
- def accept(visitor)
157
- visitor.visit_swizzle(self)
158
- end
159
- end
160
-
161
- class IfStatement < Node
162
- attr_reader :condition, :then_branch, :else_branch
163
-
164
- def initialize(condition, then_branch, else_branch = nil, type = nil)
165
- super()
166
- @condition = condition
167
- @then_branch = then_branch
168
- @else_branch = else_branch
169
- @type = type
170
- end
171
-
172
- def accept(visitor)
173
- visitor.visit_if_statement(self)
174
- end
175
- end
176
-
177
- class Return < Node
178
- attr_reader :expression
179
-
180
- def initialize(expression)
181
- super()
182
- @expression = expression
183
- @type = expression&.type
184
- end
185
-
186
- def accept(visitor)
187
- visitor.visit_return(self)
188
- end
189
- end
190
-
191
- class Assignment < Node
192
- attr_reader :target, :value
193
-
194
- def initialize(target, value)
195
- super()
196
- @target = target
197
- @value = value
198
- @type = value&.type
199
- end
200
-
201
- def accept(visitor)
202
- visitor.visit_assignment(self)
203
- end
204
- end
205
-
206
- class ForLoop < Node
207
- attr_reader :variable, :range_start, :range_end, :body
208
-
209
- def initialize(variable, range_start, range_end, body)
210
- super()
211
- @variable = variable
212
- @range_start = range_start
213
- @range_end = range_end
214
- @body = body
215
- @type = nil
216
- end
217
-
218
- def accept(visitor)
219
- visitor.visit_for_loop(self)
220
- end
221
- end
222
-
223
- class WhileLoop < Node
224
- attr_reader :condition, :body
225
-
226
- def initialize(condition, body)
227
- super()
228
- @condition = condition
229
- @body = body
230
- @type = nil
231
- end
232
-
233
- def accept(visitor)
234
- visitor.visit_while_loop(self)
235
- end
236
- end
237
-
238
- class Break < Node
239
- def initialize
240
- super()
241
- @type = nil
242
- end
243
-
244
- def accept(visitor)
245
- visitor.visit_break(self)
246
- end
247
- end
248
-
249
- class Constant < Node
250
- attr_reader :name
251
-
252
- def initialize(name, type = :float)
253
- super()
254
- @name = name
255
- @type = type
256
- end
257
-
258
- def accept(visitor)
259
- visitor.visit_constant(self)
260
- end
261
- end
262
-
263
- class Parenthesized < Node
264
- attr_reader :expression
265
-
266
- def initialize(expression)
267
- super()
268
- @expression = expression
269
- @type = expression&.type
270
- end
271
-
272
- def accept(visitor)
273
- visitor.visit_parenthesized(self)
274
- end
275
- end
276
-
277
- class ArrayLiteral < Node
278
- attr_reader :elements
279
-
280
- def initialize(elements, type = nil)
281
- super()
282
- @elements = elements
283
- @type = type
284
- end
285
-
286
- def accept(visitor)
287
- visitor.visit_array_literal(self)
288
- end
289
- end
290
-
291
- class ArrayIndex < Node
292
- attr_reader :array, :index
293
-
294
- def initialize(array, index, type = nil)
295
- super()
296
- @array = array
297
- @index = index
298
- @type = type
299
- end
300
-
301
- def accept(visitor)
302
- visitor.visit_array_index(self)
303
- end
304
- end
305
-
306
- class GlobalDecl < Node
307
- attr_reader :name, :initializer
308
- attr_accessor :is_const, :is_static, :array_size, :element_type
309
-
310
- def initialize(name, initializer, type: nil, is_const: false, is_static: true, array_size: nil, element_type: nil)
311
- super()
312
- @name = name
313
- @initializer = initializer
314
- @type = type
315
- @is_const = is_const
316
- @is_static = is_static
317
- @array_size = array_size
318
- @element_type = element_type
319
- end
320
-
321
- def accept(visitor)
322
- visitor.visit_global_decl(self)
323
- end
324
- end
325
-
326
- class FunctionDefinition < Node
327
- attr_reader :name, :params, :body
328
- attr_accessor :return_type, :param_types
329
-
330
- def initialize(name, params, body, return_type: nil, param_types: {})
331
- super()
332
- @name = name
333
- @params = params
334
- @body = body
335
- @return_type = return_type
336
- @param_types = param_types
337
- @type = return_type
338
- end
339
-
340
- def accept(visitor)
341
- visitor.visit_function_definition(self)
342
- end
343
- end
344
-
345
- class MultipleAssignment < Node
346
- attr_reader :targets, :value
347
-
348
- def initialize(targets, value)
349
- super()
350
- @targets = targets
351
- @value = value
352
- @type = nil
353
- end
354
-
355
- def accept(visitor)
356
- visitor.visit_multiple_assignment(self)
357
- end
358
- end
359
-
360
- class TupleType
361
- attr_reader :types
362
-
363
- def initialize(*types)
364
- @types = types
365
- end
366
-
367
- def to_sym
368
- :"tuple_#{types.map(&:to_s).join('_')}"
369
- end
370
- end
371
- end
372
- end
373
- end
3
+ require_relative "node"
4
+ require_relative "expressions"
5
+ require_relative "control_flow"
6
+ require_relative "definitions"
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ module IR
6
+ module Traversal
7
+ module_function
8
+
9
+ def each(node, &block)
10
+ return enum_for(:each, node) unless block_given?
11
+ return if node.nil?
12
+
13
+ yield node
14
+ child_nodes(node).each { |child| each(child, &block) }
15
+ end
16
+
17
+ def child_nodes(node)
18
+ case node
19
+ when Block
20
+ node.statements
21
+ when VarDecl
22
+ [node.initializer]
23
+ when BinaryOp
24
+ [node.left, node.right]
25
+ when UnaryOp
26
+ [node.operand]
27
+ when FuncCall
28
+ [node.receiver, *node.args]
29
+ when FieldAccess, Swizzle
30
+ [node.receiver]
31
+ when IfStatement
32
+ [node.condition, node.then_branch, node.else_branch]
33
+ when Ternary
34
+ [node.condition, node.then_expr, node.else_expr]
35
+ when Return
36
+ [node.expression]
37
+ when Assignment
38
+ [node.target, node.value]
39
+ when ForLoop
40
+ [node.range_start, node.range_end, node.body]
41
+ when WhileLoop
42
+ [node.condition, node.body]
43
+ when Parenthesized
44
+ [node.expression]
45
+ when ArrayLiteral
46
+ node.elements
47
+ when ArrayIndex
48
+ [node.array, node.index]
49
+ when GlobalDecl
50
+ [node.initializer]
51
+ when FunctionDefinition
52
+ [node.body]
53
+ when MultipleAssignment
54
+ [*node.targets, node.value]
55
+ else
56
+ []
57
+ end.compact
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ class SourceExtractor
6
+ class BlockLocator
7
+ def extract(source, start_line)
8
+ extract_unit(source, start_line).to_source
9
+ end
10
+
11
+ def extract_unit(source, start_line)
12
+ parsed = ::Prism.parse(source)
13
+ raise SourceNotAvailable, "Unable to parse block source" unless parsed.success?
14
+
15
+ block = block_at_line(parsed.value, start_line)
16
+ raise SourceNotAvailable, "Unable to locate block source" unless block
17
+
18
+ SourceUnit.from_block(block)
19
+ end
20
+
21
+ private
22
+
23
+ def block_at_line(node, start_line)
24
+ each_node(node) do |current|
25
+ next unless current.is_a?(::Prism::BlockNode)
26
+ return current if current.location.start_line == start_line
27
+ end
28
+
29
+ nil
30
+ end
31
+ def each_node(node)
32
+ return enum_for(:each_node, node) unless block_given?
33
+ return unless node
34
+
35
+ stack = [node]
36
+
37
+ until stack.empty?
38
+ current = stack.pop
39
+ yield current
40
+
41
+ children = if current.respond_to?(:compact_child_nodes)
42
+ current.compact_child_nodes
43
+ else
44
+ Array(current.child_nodes).compact
45
+ end
46
+ stack.concat(children.reverse)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,152 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "prism"
4
+
5
+ require_relative "source_unit"
6
+ require_relative "source_extractor/block_locator"
7
+
3
8
  module RLSL
4
9
  module Prism
5
10
  class SourceExtractor
6
11
  class SourceNotAvailable < StandardError; end
7
12
 
13
+ def initialize(block_locator = BlockLocator.new)
14
+ @block_locator = block_locator
15
+ end
16
+
8
17
  def extract(block)
18
+ extract_unit(block).to_source
19
+ end
20
+
21
+ def extract_unit(block)
9
22
  file, line_num = block.source_location
10
23
  raise SourceNotAvailable, "Block source location not available" unless file && File.exist?(file)
11
24
 
12
- lines = File.readlines(file)
13
- extract_block_source(lines, line_num - 1)
25
+ @block_locator.extract_unit(File.read(file), line_num)
14
26
  end
15
27
 
16
28
  def extract_from_string(source)
17
29
  source
18
30
  end
19
-
20
- private
21
-
22
- def extract_block_source(lines, start_line)
23
- source = +""
24
- depth = 0
25
- in_block = false
26
- block_start_found = false
27
-
28
- lines[start_line..].each_with_index do |line, idx|
29
- tokens = tokenize_for_blocks(line)
30
-
31
- tokens.each do |token|
32
- case token
33
- when :do, :brace_open
34
- if !block_start_found
35
- block_start_found = true
36
- in_block = true
37
- end
38
- depth += 1
39
- when :block_start
40
- depth += 1
41
- when :end, :brace_close
42
- depth -= 1
43
- end
44
- end
45
-
46
- if block_start_found
47
- if idx == 0
48
- source << extract_first_line(line)
49
- else
50
- source << line
51
- end
52
- end
53
-
54
- break if in_block && depth == 0
55
- end
56
-
57
- clean_block_source(source)
58
- end
59
-
60
- def tokenize_for_blocks(line)
61
- tokens = []
62
- in_string = nil
63
- i = 0
64
-
65
- while i < line.length
66
- char = line[i]
67
-
68
- if in_string
69
- if char == in_string && (i == 0 || line[i - 1] != "\\")
70
- in_string = nil
71
- end
72
- i += 1
73
- next
74
- end
75
-
76
- if char == '"' || char == "'"
77
- in_string = char
78
- i += 1
79
- next
80
- end
81
-
82
- break if char == "#"
83
-
84
- prev_is_boundary = i == 0 || !line[i - 1].match?(/[a-zA-Z0-9_]/)
85
-
86
- if char == "{"
87
- tokens << :brace_open
88
- elsif char == "}"
89
- tokens << :brace_close
90
- elsif prev_is_boundary && line[i..].match?(/\Ado\b/)
91
- tokens << :do
92
- i += 1
93
- elsif prev_is_boundary && line[i..].match?(/\Aelsif\b/)
94
- i += 4
95
- elsif prev_is_boundary && line[i..].match?(/\Aelse\b/)
96
- i += 3
97
- elsif prev_is_boundary && (m = line[i..].match(/\A(if|unless|while|for|case|def|class|module)\b/))
98
- tokens << :block_start
99
- i += m[1].length - 1
100
- elsif prev_is_boundary && line[i..].match?(/\Aend\b/)
101
- tokens << :end
102
- i += 2
103
- end
104
-
105
- i += 1
106
- end
107
-
108
- tokens
109
- end
110
-
111
- def extract_first_line(line)
112
- if line.include?(" do")
113
- match = line.match(/do\s*(\|[^|]*\|)?\s*(.*)$/)
114
- if match
115
- params = match[1] || ""
116
- rest = match[2] || ""
117
- "#{params}\n#{rest}\n"
118
- else
119
- "\n"
120
- end
121
- elsif line.include?("{")
122
- match = line.match(/\{\s*(\|[^|]*\|)?\s*(.*)$/)
123
- if match
124
- params = match[1] || ""
125
- rest = match[2] || ""
126
- "#{params}\n#{rest}\n"
127
- else
128
- "\n"
129
- end
130
- else
131
- line
132
- end
133
- end
134
-
135
- def clean_block_source(source)
136
- lines = source.lines
137
- return "" if lines.empty?
138
-
139
- last_line = lines.last.strip
140
- if last_line == "end" || last_line == "}"
141
- lines.pop
142
- elsif last_line.end_with?("end") || last_line.end_with?("}")
143
- lines[-1] = lines[-1].sub(/\s*(end|\})\s*$/, "\n")
144
- end
145
-
146
- lines.shift if lines.first&.strip&.empty?
147
-
148
- lines.join
149
- end
150
31
  end
151
32
  end
152
33
  end