rlsl 0.1.1 → 1.0.1

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/CHANGELOG.md +13 -2
  4. data/README.md +101 -26
  5. data/Rakefile +7 -0
  6. data/lib/rlsl/base_translator/call_parser.rb +79 -0
  7. data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
  8. data/lib/rlsl/base_translator/code_scanner.rb +140 -0
  9. data/lib/rlsl/base_translator.rb +182 -64
  10. data/lib/rlsl/code_generator/math_prelude.rb +172 -0
  11. data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +137 -0
  12. data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
  13. data/lib/rlsl/code_generator/template_context.rb +44 -0
  14. data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
  15. data/lib/rlsl/code_generator.rb +30 -202
  16. data/lib/rlsl/compiled_shader.rb +5 -13
  17. data/lib/rlsl/errors.rb +29 -0
  18. data/lib/rlsl/function_context.rb +31 -14
  19. data/lib/rlsl/glsl/translator.rb +35 -41
  20. data/lib/rlsl/msl/shader.rb +34 -46
  21. data/lib/rlsl/msl/translator.rb +38 -34
  22. data/lib/rlsl/msl/uniform_buffer_packer.rb +72 -0
  23. data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +137 -0
  24. data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +92 -0
  25. data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +172 -0
  26. data/lib/rlsl/prism/ast_visitor/scope_context.rb +48 -0
  27. data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
  28. data/lib/rlsl/prism/ast_visitor.rb +100 -286
  29. data/lib/rlsl/prism/builtins/function_registry.rb +131 -0
  30. data/lib/rlsl/prism/builtins/operator_rules.rb +123 -0
  31. data/lib/rlsl/prism/builtins/swizzle_rules.rb +47 -0
  32. data/lib/rlsl/prism/builtins.rb +39 -148
  33. data/lib/rlsl/prism/compilation_unit.rb +7 -0
  34. data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +126 -0
  35. data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +134 -0
  36. data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +108 -0
  37. data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +95 -0
  38. data/lib/rlsl/prism/emitters/base_emitter.rb +120 -414
  39. data/lib/rlsl/prism/emitters/c_emitter.rb +165 -112
  40. data/lib/rlsl/prism/emitters/glsl_emitter.rb +63 -50
  41. data/lib/rlsl/prism/emitters/msl_emitter.rb +67 -52
  42. data/lib/rlsl/prism/emitters/target_emitter.rb +124 -0
  43. data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
  44. data/lib/rlsl/prism/emitters/wgsl_emitter.rb +217 -58
  45. data/lib/rlsl/prism/errors.rb +9 -0
  46. data/lib/rlsl/prism/ir/control_flow.rb +85 -0
  47. data/lib/rlsl/prism/ir/definitions.rb +82 -0
  48. data/lib/rlsl/prism/ir/expressions.rb +201 -0
  49. data/lib/rlsl/prism/ir/node.rb +21 -0
  50. data/lib/rlsl/prism/ir/nodes.rb +4 -371
  51. data/lib/rlsl/prism/ir/traversal.rb +66 -0
  52. data/lib/rlsl/prism/mutation_analyzer.rb +30 -0
  53. data/lib/rlsl/prism/node_traversal.rb +41 -0
  54. data/lib/rlsl/prism/parameter_list.rb +46 -0
  55. data/lib/rlsl/prism/return_flow_validator.rb +73 -0
  56. data/lib/rlsl/prism/source_extractor/block_locator.rb +50 -0
  57. data/lib/rlsl/prism/source_extractor.rb +19 -137
  58. data/lib/rlsl/prism/source_unit/parser.rb +88 -0
  59. data/lib/rlsl/prism/source_unit.rb +42 -0
  60. data/lib/rlsl/prism/target_capability_validator.rb +110 -0
  61. data/lib/rlsl/prism/transpiler.rb +99 -59
  62. data/lib/rlsl/prism/type_inference/call_type_resolver.rb +59 -0
  63. data/lib/rlsl/prism/type_inference/call_validator.rb +75 -0
  64. data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +106 -0
  65. data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +147 -0
  66. data/lib/rlsl/prism/type_inference/definition_inferer.rb +56 -0
  67. data/lib/rlsl/prism/type_inference/expression_inferer.rb +96 -0
  68. data/lib/rlsl/prism/type_inference/field_type_resolver.rb +38 -0
  69. data/lib/rlsl/prism/type_inference/inferer_registry.rb +38 -0
  70. data/lib/rlsl/prism/type_inference/scope_stack.rb +47 -0
  71. data/lib/rlsl/prism/type_inference/type_environment.rb +112 -0
  72. data/lib/rlsl/prism/type_inference/type_shapes.rb +33 -0
  73. data/lib/rlsl/prism/type_inference.rb +120 -249
  74. data/lib/rlsl/runtime_shader.rb +47 -0
  75. data/lib/rlsl/shader_builder/build_service.rb +104 -0
  76. data/lib/rlsl/shader_builder/native_extension_compiler.rb +97 -0
  77. data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
  78. data/lib/rlsl/shader_builder/source_resolver.rb +109 -0
  79. data/lib/rlsl/shader_builder.rb +60 -111
  80. data/lib/rlsl/shader_name.rb +18 -0
  81. data/lib/rlsl/types/catalog.rb +47 -0
  82. data/lib/rlsl/types/target_resolver.rb +15 -0
  83. data/lib/rlsl/types/type_spec.rb +167 -0
  84. data/lib/rlsl/types/value_normalizer.rb +86 -0
  85. data/lib/rlsl/types.rb +9 -31
  86. data/lib/rlsl/uniform_context.rb +22 -11
  87. data/lib/rlsl/version.rb +1 -1
  88. data/lib/rlsl/wgsl/translator.rb +46 -39
  89. data/lib/rlsl/wgsl/uniform_layout.rb +25 -0
  90. data/lib/rlsl.rb +38 -15
  91. metadata +76 -11
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ module Builtins
6
+ module OperatorRules
7
+ BINARY_OPERATORS = {
8
+ "+" => :arithmetic,
9
+ "-" => :arithmetic,
10
+ "*" => :arithmetic,
11
+ "/" => :arithmetic,
12
+ "%" => :arithmetic,
13
+
14
+ "==" => :comparison,
15
+ "!=" => :comparison,
16
+ "<" => :comparison,
17
+ ">" => :comparison,
18
+ "<=" => :comparison,
19
+ ">=" => :comparison,
20
+
21
+ "&&" => :logical,
22
+ "||" => :logical
23
+ }.freeze
24
+
25
+ UNARY_OPERATORS = {
26
+ "-" => :negate,
27
+ "!" => :not
28
+ }.freeze
29
+
30
+ module_function
31
+
32
+ def binary_operator?(op)
33
+ BINARY_OPERATORS.key?(op.to_s)
34
+ end
35
+
36
+ def unary_operator?(op)
37
+ UNARY_OPERATORS.key?(op.to_s)
38
+ end
39
+
40
+ def binary_op_result_type(op, left_type, right_type)
41
+ op_kind = BINARY_OPERATORS[op.to_s]
42
+ validate_operand_shapes!(op, left_type, right_type)
43
+
44
+ case op_kind
45
+ when :comparison, :logical
46
+ :bool
47
+ when :arithmetic
48
+ if matrix_type?(left_type) && vector_type?(right_type)
49
+ matrix_vector_result(left_type)
50
+ elsif vector_type?(left_type) && matrix_type?(right_type)
51
+ matrix_vector_result(right_type)
52
+ elsif matrix_type?(left_type) && matrix_type?(right_type)
53
+ left_type
54
+ elsif matrix_type?(left_type) && scalar_type?(right_type)
55
+ left_type
56
+ elsif scalar_type?(left_type) && matrix_type?(right_type)
57
+ right_type
58
+ elsif vector_type?(left_type) && vector_type?(right_type)
59
+ left_type
60
+ elsif vector_type?(left_type) && scalar_type?(right_type)
61
+ left_type
62
+ elsif scalar_type?(left_type) && vector_type?(right_type)
63
+ right_type
64
+ else
65
+ scalar_arithmetic_result_type(op, left_type, right_type)
66
+ end
67
+ end
68
+ end
69
+
70
+ def vector_type?(type)
71
+ %i[vec2 vec3 vec4].include?(type)
72
+ end
73
+
74
+ def matrix_type?(type)
75
+ %i[mat2 mat3 mat4].include?(type)
76
+ end
77
+
78
+ def scalar_type?(type)
79
+ %i[float int].include?(type)
80
+ end
81
+
82
+ def common_type(types)
83
+ types = Array(types).compact.uniq
84
+ return types.first if types.length == 1
85
+ return :float if types.sort == %i[float int]
86
+
87
+ nil
88
+ end
89
+
90
+ def scalar_arithmetic_result_type(op, left_type, right_type)
91
+ return :float unless scalar_type?(left_type) && scalar_type?(right_type)
92
+ return :float if op.to_s == "/"
93
+ return :int if left_type == :int && right_type == :int
94
+
95
+ :float
96
+ end
97
+
98
+ def matrix_vector_result(matrix_type)
99
+ case matrix_type
100
+ when :mat2 then :vec2
101
+ when :mat3 then :vec3
102
+ when :mat4 then :vec4
103
+ end
104
+ end
105
+
106
+ def validate_operand_shapes!(op, left_type, right_type)
107
+ if vector_type?(left_type) && vector_type?(right_type) && left_type != right_type
108
+ raise SignatureError, "Vector size mismatch for #{op}: #{left_type} and #{right_type}"
109
+ end
110
+
111
+ if matrix_type?(left_type) && vector_type?(right_type) && matrix_vector_result(left_type) != right_type
112
+ raise SignatureError, "Matrix/vector size mismatch for #{op}: #{left_type} and #{right_type}"
113
+ end
114
+
115
+ return unless vector_type?(left_type) && matrix_type?(right_type)
116
+ return if left_type == matrix_vector_result(right_type)
117
+
118
+ raise SignatureError, "Vector/matrix size mismatch for #{op}: #{left_type} and #{right_type}"
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ module Builtins
6
+ module SwizzleRules
7
+ SWIZZLE_COMPONENTS = {
8
+ "x" => 0, "r" => 0, "s" => 0,
9
+ "y" => 1, "g" => 1, "t" => 1,
10
+ "z" => 2, "b" => 2, "p" => 2,
11
+ "w" => 3, "a" => 3, "q" => 3
12
+ }.freeze
13
+
14
+ SINGLE_COMPONENT_FIELDS = %w[x y z w r g b a s t p q].freeze
15
+ SWIZZLE_PATTERNS = /\A(?:[xyzw]{2,4}|[rgba]{2,4}|[stpq]{2,4})\z/
16
+
17
+ module_function
18
+
19
+ def single_component_field?(name)
20
+ SINGLE_COMPONENT_FIELDS.include?(name.to_s)
21
+ end
22
+
23
+ def swizzle?(name)
24
+ name.to_s.match?(SWIZZLE_PATTERNS)
25
+ end
26
+
27
+ def swizzle_type(components)
28
+ case components.length
29
+ when 2 then :vec2
30
+ when 3 then :vec3
31
+ when 4 then :vec4
32
+ else :float
33
+ end
34
+ end
35
+
36
+ def valid_for_type?(components, receiver_type)
37
+ vector_size = { vec2: 2, vec3: 3, vec4: 4 }[receiver_type]
38
+ return false unless vector_size
39
+
40
+ components.to_s.each_char.all? do |component|
41
+ SWIZZLE_COMPONENTS.fetch(component) < vector_size
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,195 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "builtins/function_registry"
4
+ require_relative "builtins/operator_rules"
5
+ require_relative "builtins/swizzle_rules"
6
+
3
7
  module RLSL
4
8
  module Prism
5
9
  module Builtins
6
- FUNCTIONS = {
7
- vec2: { args: %i[any any], returns: :vec2, variadic: true, min_args: 1 },
8
- vec3: { args: %i[any any any], returns: :vec3, variadic: true, min_args: 1 },
9
- vec4: { args: %i[any any any any], returns: :vec4, variadic: true, min_args: 1 },
10
-
11
- mat2: { args: %i[any any any any], returns: :mat2, variadic: true, min_args: 1 },
12
- mat3: { args: %i[any any any any any any any any any], returns: :mat3, variadic: true, min_args: 1 },
13
- mat4: { args: %i[any any any any any any any any any any any any any any any any], returns: :mat4, variadic: true, min_args: 1 },
14
-
15
- sin: { args: [:float], returns: :float },
16
- cos: { args: [:float], returns: :float },
17
- tan: { args: [:float], returns: :float },
18
- asin: { args: [:float], returns: :float },
19
- acos: { args: [:float], returns: :float },
20
- atan: { args: %i[float float], returns: :float, variadic: true, min_args: 1 },
21
- atan2: { args: %i[float float], returns: :float },
22
-
23
- pow: { args: %i[float float], returns: :float },
24
- exp: { args: [:float], returns: :float },
25
- log: { args: [:float], returns: :float },
26
- sqrt: { args: [:any], returns: :same },
27
-
28
- abs: { args: [:any], returns: :same },
29
- sign: { args: [:any], returns: :same },
30
- floor: { args: [:any], returns: :same },
31
- ceil: { args: [:any], returns: :same },
32
- fract: { args: [:any], returns: :same },
33
- mod: { args: %i[any float], returns: :first },
34
- min: { args: %i[any any], returns: :first },
35
- max: { args: %i[any any], returns: :first },
36
- clamp: { args: %i[any any any], returns: :first },
37
- mix: { args: %i[any any float], returns: :first },
38
- step: { args: %i[float any], returns: :second },
39
- smoothstep: { args: %i[float float any], returns: :third },
40
-
41
- length: { args: [:any], returns: :float },
42
- distance: { args: %i[any any], returns: :float },
43
- dot: { args: %i[any any], returns: :float },
44
- cross: { args: %i[vec3 vec3], returns: :vec3 },
45
- normalize: { args: [:any], returns: :same },
46
- reflect: { args: %i[any any], returns: :first },
47
- refract: { args: %i[any any float], returns: :first },
48
-
49
- hash21: { args: [:vec2], returns: :float },
50
- hash22: { args: [:vec2], returns: :vec2 },
51
-
52
- lessThan: { args: %i[any any], returns: :bool },
53
- lessThanEqual: { args: %i[any any], returns: :bool },
54
- greaterThan: { args: %i[any any], returns: :bool },
55
- greaterThanEqual: { args: %i[any any], returns: :bool },
56
- equal: { args: %i[any any], returns: :bool },
57
- notEqual: { args: %i[any any], returns: :bool },
58
-
59
- inverse: { args: [:any], returns: :same },
60
- transpose: { args: [:any], returns: :same },
61
- determinant: { args: [:any], returns: :float },
62
-
63
- texture2D: { args: %i[sampler2D vec2], returns: :vec4 },
64
- texture: { args: %i[sampler2D vec2], returns: :vec4 },
65
- textureLod: { args: %i[sampler2D vec2 float], returns: :vec4 }
66
- }.freeze
67
-
68
- BINARY_OPERATORS = {
69
- "+" => :arithmetic,
70
- "-" => :arithmetic,
71
- "*" => :arithmetic,
72
- "/" => :arithmetic,
73
- "%" => :arithmetic,
74
-
75
- "==" => :comparison,
76
- "!=" => :comparison,
77
- "<" => :comparison,
78
- ">" => :comparison,
79
- "<=" => :comparison,
80
- ">=" => :comparison,
81
-
82
- "&&" => :logical,
83
- "||" => :logical
84
- }.freeze
85
-
86
- UNARY_OPERATORS = {
87
- "-" => :negate,
88
- "!" => :not
89
- }.freeze
90
-
91
- SWIZZLE_COMPONENTS = {
92
- "x" => 0, "r" => 0, "s" => 0,
93
- "y" => 1, "g" => 1, "t" => 1,
94
- "z" => 2, "b" => 2, "p" => 2,
95
- "w" => 3, "a" => 3, "q" => 3
96
- }.freeze
97
-
98
- SINGLE_COMPONENT_FIELDS = %w[x y z w r g b a s t p q].freeze
99
-
100
- SWIZZLE_PATTERNS = /\A[xyzwrgba]{2,4}\z/
10
+ FUNCTIONS = FunctionRegistry::FUNCTIONS
11
+ BINARY_OPERATORS = OperatorRules::BINARY_OPERATORS
12
+ UNARY_OPERATORS = OperatorRules::UNARY_OPERATORS
13
+ SWIZZLE_COMPONENTS = SwizzleRules::SWIZZLE_COMPONENTS
14
+ SINGLE_COMPONENT_FIELDS = SwizzleRules::SINGLE_COMPONENT_FIELDS
15
+ SWIZZLE_PATTERNS = SwizzleRules::SWIZZLE_PATTERNS
101
16
 
102
17
  class << self
103
18
  def function?(name)
104
- FUNCTIONS.key?(name.to_sym)
19
+ FunctionRegistry.function?(name)
105
20
  end
106
21
 
107
22
  def function_signature(name)
108
- FUNCTIONS[name.to_sym]
23
+ FunctionRegistry.function_signature(name)
24
+ end
25
+
26
+ def supported_on_target?(name, target)
27
+ FunctionRegistry.supported_on_target?(name, target)
28
+ end
29
+
30
+ def explicit_types(name)
31
+ FunctionRegistry.explicit_types(name)
109
32
  end
110
33
 
111
34
  def binary_operator?(op)
112
- BINARY_OPERATORS.key?(op.to_s)
35
+ OperatorRules.binary_operator?(op)
113
36
  end
114
37
 
115
38
  def unary_operator?(op)
116
- UNARY_OPERATORS.key?(op.to_s)
39
+ OperatorRules.unary_operator?(op)
117
40
  end
118
41
 
119
42
  def single_component_field?(name)
120
- SINGLE_COMPONENT_FIELDS.include?(name.to_s)
43
+ SwizzleRules.single_component_field?(name)
121
44
  end
122
45
 
123
46
  def swizzle?(name)
124
- name.to_s.match?(SWIZZLE_PATTERNS)
47
+ SwizzleRules.swizzle?(name)
125
48
  end
126
49
 
127
50
  def swizzle_type(components)
128
- case components.length
129
- when 2 then :vec2
130
- when 3 then :vec3
131
- when 4 then :vec4
132
- else :float
133
- end
51
+ SwizzleRules.swizzle_type(components)
52
+ end
53
+
54
+ def valid_swizzle_for_type?(components, receiver_type)
55
+ SwizzleRules.valid_for_type?(components, receiver_type)
134
56
  end
135
57
 
136
58
  def resolve_return_type(rule, arg_types)
137
- case rule
138
- when :same then arg_types.first
139
- when :first then arg_types.first
140
- when :second then arg_types[1]
141
- when :third then arg_types[2]
142
- when Symbol then rule
143
- end
59
+ FunctionRegistry.resolve_return_type(rule, arg_types)
144
60
  end
145
61
 
146
62
  def binary_op_result_type(op, left_type, right_type)
147
- op_kind = BINARY_OPERATORS[op.to_s]
148
-
149
- case op_kind
150
- when :comparison, :logical
151
- :bool
152
- when :arithmetic
153
- if matrix_type?(left_type) && vector_type?(right_type)
154
- matrix_vector_result(left_type)
155
- elsif vector_type?(left_type) && matrix_type?(right_type)
156
- matrix_vector_result(right_type)
157
- elsif matrix_type?(left_type) && matrix_type?(right_type)
158
- left_type
159
- elsif matrix_type?(left_type) && scalar_type?(right_type)
160
- left_type
161
- elsif scalar_type?(left_type) && matrix_type?(right_type)
162
- right_type
163
- elsif vector_type?(left_type) && vector_type?(right_type)
164
- left_type
165
- elsif vector_type?(left_type) && scalar_type?(right_type)
166
- left_type
167
- elsif scalar_type?(left_type) && vector_type?(right_type)
168
- right_type
169
- else
170
- :float
171
- end
172
- end
63
+ OperatorRules.binary_op_result_type(op, left_type, right_type)
173
64
  end
174
65
 
175
66
  def vector_type?(type)
176
- %i[vec2 vec3 vec4].include?(type)
67
+ OperatorRules.vector_type?(type)
177
68
  end
178
69
 
179
70
  def matrix_type?(type)
180
- %i[mat2 mat3 mat4].include?(type)
71
+ OperatorRules.matrix_type?(type)
181
72
  end
182
73
 
183
74
  def scalar_type?(type)
184
- %i[float int].include?(type)
75
+ OperatorRules.scalar_type?(type)
76
+ end
77
+
78
+ def common_type(types)
79
+ OperatorRules.common_type(types)
185
80
  end
186
81
 
187
82
  def matrix_vector_result(matrix_type)
188
- case matrix_type
189
- when :mat2 then :vec2
190
- when :mat3 then :vec3
191
- when :mat4 then :vec4
192
- end
83
+ OperatorRules.matrix_vector_result(matrix_type)
193
84
  end
194
85
  end
195
86
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ CompilationUnit = Struct.new(:source_unit, :ir, keyword_init: true)
6
+ end
7
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ module Emitters
6
+ class BaseEmitter
7
+ module ControlFlowEmission
8
+ def emit_tuple_return(node)
9
+ "#{indent}return #{emit_tuple_value(node)};\n"
10
+ end
11
+
12
+ def emit_if_statement(node)
13
+ emit_conditional(node, needs_return: return_context?)
14
+ end
15
+
16
+ def emit_conditional(node, needs_return:)
17
+ condition = emit(node.condition)
18
+ then_code = emit_branch(node.then_branch, needs_return: needs_return)
19
+ declarations = emit_hoisted_declarations(node)
20
+
21
+ unless node.else_branch
22
+ return "#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}}#{needs_return ? "\n" : ""}"
23
+ end
24
+
25
+ if elsif_node?(node.else_branch)
26
+ elsif_code = emit_elsif(node.else_branch, needs_return: needs_return)
27
+ "#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}#{needs_return ? "\n" : ""}"
28
+ else
29
+ else_code = emit_branch(node.else_branch, needs_return: needs_return)
30
+ "#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}#{needs_return ? "\n" : ""}"
31
+ end
32
+ end
33
+
34
+ def emit_elsif(node, needs_return: false)
35
+ if_node = node.is_a?(IR::Block) ? node.statements.first : node
36
+ condition = emit(if_node.condition)
37
+ then_code = emit_branch(if_node.then_branch, needs_return: needs_return)
38
+
39
+ return "else if (#{condition}) {\n#{then_code}#{indent}}" unless if_node.else_branch
40
+
41
+ if elsif_node?(if_node.else_branch)
42
+ elsif_code = emit_elsif(if_node.else_branch, needs_return: needs_return)
43
+ "else if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}"
44
+ else
45
+ else_code = emit_branch(if_node.else_branch, needs_return: needs_return)
46
+ "else if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}"
47
+ end
48
+ end
49
+
50
+ def elsif_node?(node)
51
+ return true if node.is_a?(IR::IfStatement)
52
+ return false unless node.is_a?(IR::Block)
53
+
54
+ node.statements.length == 1 && node.statements.first.is_a?(IR::IfStatement)
55
+ end
56
+
57
+ def emit_return(node)
58
+ if node.expression.is_a?(IR::ArrayLiteral) && @return_struct_name_stack.any?
59
+ return "return #{emit_tuple_value(node.expression)}"
60
+ end
61
+
62
+ node.expression ? "return #{emit_return_expression(node.expression)}" : "return"
63
+ end
64
+
65
+ def emit_for_loop(node)
66
+ variable = node.variable
67
+ counter = loop_variable_mutated?(node) ? next_temporary_name("i") : variable
68
+ start_val = emit(node.range_start)
69
+ end_val = emit(node.range_end)
70
+ body = emit_indented_block(node.body)
71
+ body = "#{indent} #{type_name(:int)} #{variable} = #{counter};\n#{body}" if counter != variable
72
+
73
+ comparison = node.exclude_end ? "<" : "<="
74
+ return "for (int #{counter} = #{start_val}; #{counter} #{comparison} #{end_val}; #{counter}++) {\n#{body}#{indent}}" if node.range_end.is_a?(IR::Literal)
75
+
76
+ bound = next_temporary_name("end")
77
+ "int #{bound} = #{end_val};\n#{indent}for (int #{counter} = #{start_val}; #{counter} #{comparison} #{bound}; #{counter}++) {\n#{body}#{indent}}"
78
+ end
79
+
80
+ def emit_while_loop(node)
81
+ condition = emit(node.condition)
82
+ body = emit_indented_block(node.body)
83
+
84
+ "while (#{condition}) {\n#{body}#{indent}}"
85
+ end
86
+
87
+ def emit_break(_node)
88
+ "break"
89
+ end
90
+
91
+ def emit_hoisted_declarations(node)
92
+ node.hoisted_variables.map do |name, type|
93
+ "#{indent}#{type_name(type || :float)} #{name};\n"
94
+ end.join
95
+ end
96
+
97
+ def emit_tuple_value(node)
98
+ expected_types = Array(current_return_type)
99
+ elements = node.elements.each_with_index.map do |element, index|
100
+ emit_typed_argument(element, expected_types[index])
101
+ end.join(", ")
102
+ "(#{current_return_struct_name}){#{elements}}"
103
+ end
104
+
105
+ def emit_return_expression(node)
106
+ emit_typed_argument(node, current_return_type)
107
+ end
108
+
109
+ def loop_variable_mutated?(node)
110
+ IR::Traversal.each(node.body).any? do |current|
111
+ case current
112
+ when IR::Assignment
113
+ current.target.is_a?(IR::VarRef) && current.target.name == node.variable
114
+ when IR::MultipleAssignment
115
+ current.targets.any? { |target| target.name == node.variable }
116
+ else
117
+ false
118
+ end
119
+ end
120
+ end
121
+
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RLSL
4
+ module Prism
5
+ module Emitters
6
+ class BaseEmitter
7
+ module DefinitionEmission
8
+ def emit_function_definition(node)
9
+ name = node.name
10
+ params = node.params.map do |param|
11
+ "#{type_name(node.param_types[param] || :float)} #{param}"
12
+ end.join(", ")
13
+
14
+ if node.return_type.is_a?(Array)
15
+ struct_def = emit_result_struct(name, node.return_type)
16
+ body = with_return_struct_name("#{name}_result") do
17
+ with_return_type(node.return_type) { emit_indented_block(node.body, needs_return: true) }
18
+ end
19
+ "#{struct_def}#{function_qualifier}#{name}_result #{name}(#{params}) {\n#{body}#{indent}}\n"
20
+ else
21
+ body = with_return_type(node.return_type) { emit_indented_block(node.body, needs_return: true) }
22
+ "#{function_qualifier}#{type_name(node.return_type || :float)} #{name}(#{params}) {\n#{body}#{indent}}\n"
23
+ end
24
+ end
25
+
26
+ def emit_result_struct(func_name, types)
27
+ fields = types.each_with_index.map { |type, index| "#{type_name(type)} v#{index};" }.join(" ")
28
+ "typedef struct { #{fields} } #{func_name}_result;\n"
29
+ end
30
+
31
+ def current_return_struct_name
32
+ @return_struct_name_stack.last || "result"
33
+ end
34
+
35
+ def emit_array_literal(node, for_static_init: false)
36
+ element_type = TypeShapes.element_type(node.type)
37
+ elements = node.elements.map do |element|
38
+ if for_static_init
39
+ emit_for_static_init(element, true)
40
+ else
41
+ emit_typed_argument(element, element_type)
42
+ end
43
+ end.join(", ")
44
+ "{#{elements}}"
45
+ end
46
+
47
+ def emit_for_static_init(node, for_static_init)
48
+ return emit(node) unless for_static_init
49
+
50
+ case node
51
+ when IR::FuncCall
52
+ if %i[vec2 vec3 vec4].include?(node.name)
53
+ args = node.args.map { |arg| emit_for_static_init(arg, true) }.join(", ")
54
+ "{#{args}}"
55
+ else
56
+ emit(node)
57
+ end
58
+ when IR::ArrayLiteral
59
+ emit_array_literal(node, for_static_init: true)
60
+ else
61
+ emit(node)
62
+ end
63
+ end
64
+
65
+ def emit_global_decl(node)
66
+ prefix = ""
67
+ prefix += "static " if node.is_static
68
+ prefix += "const " if node.is_const
69
+
70
+ if node.initializer.is_a?(IR::ArrayLiteral)
71
+ elem_type = type_name(node.element_type || :float)
72
+ size = node.array_size || node.initializer.elements.length
73
+ elements = emit_array_literal(node.initializer, for_static_init: true)
74
+ "#{prefix}#{elem_type} #{node.name}[#{size}] = #{elements}"
75
+ else
76
+ value = node.is_static ? emit_for_static_init(node.initializer, true) : emit(node.initializer)
77
+ "#{prefix}#{type_name(node.type || :float)} #{node.name} = #{value}"
78
+ end
79
+ end
80
+
81
+ def emit_multiple_assignment(node)
82
+ value_code = emit(node.value)
83
+
84
+ if node.value.is_a?(IR::FuncCall)
85
+ emit_multi_return_assignment(node, value_code)
86
+ elsif node.value.is_a?(IR::ArrayLiteral)
87
+ emit_literal_assignment(node)
88
+ else
89
+ emit_indexed_assignment(node, value_code)
90
+ end
91
+ end
92
+
93
+ private
94
+
95
+ def emit_multi_return_assignment(node, value_code)
96
+ func_name = node.value.name
97
+ temporary = next_temporary_name("result")
98
+ lines = [emit_temporary_declaration("#{func_name}_result", temporary, value_code)]
99
+ node.targets.each_with_index do |target, index|
100
+ lines << "#{emit_multiple_assignment_target(target, node.declarations[index])} = #{temporary}.v#{index}"
101
+ end
102
+ lines.join(";\n#{indent}")
103
+ end
104
+
105
+ def emit_indexed_assignment(node, value_code)
106
+ node.targets.each_with_index.map do |target, index|
107
+ "#{emit_multiple_assignment_target(target, node.declarations[index])} = #{value_code}[#{index}]"
108
+ end.join(";\n#{indent}")
109
+ end
110
+
111
+ def emit_literal_assignment(node)
112
+ temporaries = node.value.elements.map do |element|
113
+ name = next_temporary_name("value")
114
+ [name, emit_temporary_declaration(type_name(element.type || :float), name, emit(element))]
115
+ end
116
+ lines = temporaries.map(&:last)
117
+ node.targets.each_with_index do |target, index|
118
+ lines << "#{emit_multiple_assignment_target(target, node.declarations[index])} = #{temporaries[index].first}"
119
+ end
120
+ lines.join(";\n#{indent}")
121
+ end
122
+
123
+ def emit_multiple_assignment_target(target, declaration)
124
+ declaration ? "#{type_name(target.type || :float)} #{target.name}" : target.name.to_s
125
+ end
126
+
127
+ def emit_temporary_declaration(type, name, value)
128
+ "#{type} #{name} = #{value}"
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end