rlsl 1.0.0 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +3 -1
- data/README.md +101 -28
- data/Rakefile +7 -0
- data/lib/rlsl/base_translator/call_parser.rb +13 -2
- data/lib/rlsl/base_translator/code_scanner.rb +39 -1
- data/lib/rlsl/base_translator.rb +24 -2
- data/lib/rlsl/code_generator/math_prelude.rb +103 -10
- data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +52 -12
- data/lib/rlsl/code_generator/template_context.rb +6 -3
- data/lib/rlsl/code_generator/uniform_struct_generator.rb +1 -1
- data/lib/rlsl/code_generator.rb +7 -4
- data/lib/rlsl/compiled_shader.rb +1 -1
- data/lib/rlsl/errors.rb +29 -0
- data/lib/rlsl/glsl/translator.rb +19 -6
- data/lib/rlsl/msl/shader.rb +27 -9
- data/lib/rlsl/msl/translator.rb +25 -4
- data/lib/rlsl/msl/uniform_buffer_packer.rb +11 -7
- data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +59 -18
- data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +22 -9
- data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +18 -14
- data/lib/rlsl/prism/ast_visitor/scope_context.rb +4 -0
- data/lib/rlsl/prism/ast_visitor.rb +78 -20
- data/lib/rlsl/prism/builtins/function_registry.rb +41 -24
- data/lib/rlsl/prism/builtins/operator_rules.rb +24 -0
- data/lib/rlsl/prism/builtins/swizzle_rules.rb +10 -1
- data/lib/rlsl/prism/builtins.rb +8 -0
- data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +51 -8
- data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +42 -12
- data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +20 -4
- data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +7 -1
- data/lib/rlsl/prism/emitters/base_emitter.rb +66 -5
- data/lib/rlsl/prism/emitters/c_emitter.rb +103 -7
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +48 -0
- data/lib/rlsl/prism/emitters/msl_emitter.rb +43 -1
- data/lib/rlsl/prism/emitters/target_emitter.rb +56 -9
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +173 -18
- data/lib/rlsl/prism/errors.rb +9 -0
- data/lib/rlsl/prism/ir/control_flow.rb +6 -4
- data/lib/rlsl/prism/ir/definitions.rb +17 -2
- data/lib/rlsl/prism/ir/expressions.rb +5 -1
- data/lib/rlsl/prism/ir/node.rb +1 -1
- data/lib/rlsl/prism/ir/traversal.rb +6 -2
- data/lib/rlsl/prism/mutation_analyzer.rb +30 -0
- data/lib/rlsl/prism/node_traversal.rb +41 -0
- data/lib/rlsl/prism/parameter_list.rb +46 -0
- data/lib/rlsl/prism/return_flow_validator.rb +73 -0
- data/lib/rlsl/prism/source_extractor/block_locator.rb +23 -25
- data/lib/rlsl/prism/source_extractor.rb +7 -6
- data/lib/rlsl/prism/source_unit/parser.rb +42 -32
- data/lib/rlsl/prism/source_unit.rb +10 -10
- data/lib/rlsl/prism/target_capability_validator.rb +27 -2
- data/lib/rlsl/prism/transpiler.rb +40 -3
- data/lib/rlsl/prism/type_inference/call_type_resolver.rb +28 -4
- data/lib/rlsl/prism/type_inference/call_validator.rb +5 -1
- data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +45 -19
- data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +88 -7
- data/lib/rlsl/prism/type_inference/definition_inferer.rb +16 -1
- data/lib/rlsl/prism/type_inference/expression_inferer.rb +4 -0
- data/lib/rlsl/prism/type_inference/field_type_resolver.rb +23 -2
- data/lib/rlsl/prism/type_inference/scope_stack.rb +1 -1
- data/lib/rlsl/prism/type_inference/type_shapes.rb +3 -3
- data/lib/rlsl/prism/type_inference.rb +10 -5
- data/lib/rlsl/shader_builder/build_service.rb +34 -7
- data/lib/rlsl/shader_builder/native_extension_compiler.rb +50 -24
- data/lib/rlsl/shader_builder/shader_definition.rb +3 -3
- data/lib/rlsl/shader_builder/source_resolver.rb +19 -1
- data/lib/rlsl/shader_builder.rb +50 -10
- data/lib/rlsl/shader_name.rb +18 -0
- data/lib/rlsl/types/type_spec.rb +3 -3
- data/lib/rlsl/types/value_normalizer.rb +16 -11
- data/lib/rlsl/types.rb +0 -4
- data/lib/rlsl/uniform_context.rb +18 -1
- data/lib/rlsl/version.rb +1 -1
- data/lib/rlsl/wgsl/translator.rb +29 -6
- data/lib/rlsl/wgsl/uniform_layout.rb +25 -0
- data/lib/rlsl.rb +24 -3
- metadata +23 -11
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
require_relative "../ir/traversal"
|
|
3
6
|
require_relative "base_emitter/control_flow_emission"
|
|
4
7
|
require_relative "base_emitter/expression_emission"
|
|
5
8
|
require_relative "base_emitter/definition_emission"
|
|
@@ -66,14 +69,26 @@ module RLSL
|
|
|
66
69
|
def initialize
|
|
67
70
|
@indent_level = 0
|
|
68
71
|
@return_context_stack = [false]
|
|
72
|
+
@return_struct_name_stack = []
|
|
73
|
+
@return_type_stack = []
|
|
74
|
+
@temporary_index = 0
|
|
75
|
+
@emit_depth = 0
|
|
76
|
+
@occupied_names = Set.new
|
|
69
77
|
end
|
|
70
78
|
|
|
71
79
|
def emit(node, needs_return: false)
|
|
80
|
+
@occupied_names = source_names(node) if @emit_depth.zero?
|
|
81
|
+
@emit_depth += 1
|
|
72
82
|
with_return_context(needs_return) do
|
|
73
83
|
return node.accept(self) if node.respond_to?(:accept)
|
|
74
84
|
|
|
75
|
-
raise "Unknown IR node: #{node.class}"
|
|
85
|
+
raise RLSL::InternalError, "Unknown IR node: #{node.class}"
|
|
76
86
|
end
|
|
87
|
+
rescue RLSL::Error => error
|
|
88
|
+
error.with_source_location(node.location) if node.respond_to?(:location)
|
|
89
|
+
raise
|
|
90
|
+
ensure
|
|
91
|
+
@emit_depth -= 1
|
|
77
92
|
end
|
|
78
93
|
|
|
79
94
|
protected
|
|
@@ -82,13 +97,15 @@ module RLSL
|
|
|
82
97
|
type.to_s
|
|
83
98
|
end
|
|
84
99
|
|
|
85
|
-
def format_number(value)
|
|
100
|
+
def format_number(value, type: nil)
|
|
101
|
+
return value.to_i.to_s if type == :int || value.is_a?(Integer)
|
|
102
|
+
|
|
86
103
|
if value.is_a?(Float)
|
|
87
104
|
formatted = value.to_s
|
|
88
105
|
formatted += ".0" unless formatted.include?(".")
|
|
89
106
|
formatted
|
|
90
107
|
else
|
|
91
|
-
|
|
108
|
+
value.to_s
|
|
92
109
|
end
|
|
93
110
|
end
|
|
94
111
|
|
|
@@ -96,19 +113,42 @@ module RLSL
|
|
|
96
113
|
" " * @indent_level
|
|
97
114
|
end
|
|
98
115
|
|
|
99
|
-
def emit_with_precedence(node, parent_op)
|
|
116
|
+
def emit_with_precedence(node, parent_op, side: :left)
|
|
100
117
|
code = emit(node)
|
|
101
118
|
return code unless node.is_a?(IR::BinaryOp)
|
|
102
119
|
|
|
103
120
|
node_prec = PRECEDENCE[node.operator] || 10
|
|
104
121
|
parent_prec = PRECEDENCE[parent_op] || 10
|
|
105
|
-
node_prec < parent_prec
|
|
122
|
+
needs_parentheses = node_prec < parent_prec || (side == :right && node_prec == parent_prec)
|
|
123
|
+
needs_parentheses ? "(#{code})" : code
|
|
106
124
|
end
|
|
107
125
|
|
|
108
126
|
def function_name(name)
|
|
109
127
|
name.to_s
|
|
110
128
|
end
|
|
111
129
|
|
|
130
|
+
def function_qualifier
|
|
131
|
+
"static inline "
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def with_return_struct_name(name)
|
|
135
|
+
@return_struct_name_stack << name
|
|
136
|
+
yield
|
|
137
|
+
ensure
|
|
138
|
+
@return_struct_name_stack.pop
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def with_return_type(type)
|
|
142
|
+
@return_type_stack << type
|
|
143
|
+
yield
|
|
144
|
+
ensure
|
|
145
|
+
@return_type_stack.pop
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def current_return_type
|
|
149
|
+
@return_type_stack.last
|
|
150
|
+
end
|
|
151
|
+
|
|
112
152
|
def with_return_context(enabled)
|
|
113
153
|
@return_context_stack << enabled
|
|
114
154
|
yield
|
|
@@ -119,6 +159,27 @@ module RLSL
|
|
|
119
159
|
def return_context?
|
|
120
160
|
@return_context_stack.last
|
|
121
161
|
end
|
|
162
|
+
|
|
163
|
+
def next_temporary_name(prefix)
|
|
164
|
+
loop do
|
|
165
|
+
name = :"_rlsl_#{prefix}#{@temporary_index}"
|
|
166
|
+
@temporary_index += 1
|
|
167
|
+
next if @occupied_names.include?(name)
|
|
168
|
+
|
|
169
|
+
@occupied_names.add(name)
|
|
170
|
+
return name
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def source_names(node)
|
|
175
|
+
IR::Traversal.each(node).filter_map do |current|
|
|
176
|
+
if current.respond_to?(:name)
|
|
177
|
+
current.name.to_sym
|
|
178
|
+
elsif current.is_a?(IR::ForLoop)
|
|
179
|
+
current.variable.to_sym
|
|
180
|
+
end
|
|
181
|
+
end.to_set
|
|
182
|
+
end
|
|
122
183
|
end
|
|
123
184
|
end
|
|
124
185
|
end
|
|
@@ -47,10 +47,12 @@ module RLSL
|
|
|
47
47
|
abs: "fabsf",
|
|
48
48
|
floor: "floorf",
|
|
49
49
|
ceil: "ceilf",
|
|
50
|
+
sign: "sign_f",
|
|
51
|
+
step: "step_f",
|
|
50
52
|
min: "fminf",
|
|
51
53
|
max: "fmaxf",
|
|
52
54
|
fract: "fract",
|
|
53
|
-
mod: "
|
|
55
|
+
mod: "rlsl_mod",
|
|
54
56
|
clamp: "clamp_f",
|
|
55
57
|
mix: "mix_f",
|
|
56
58
|
smoothstep: "smoothstep",
|
|
@@ -70,27 +72,72 @@ module RLSL
|
|
|
70
72
|
|
|
71
73
|
protected
|
|
72
74
|
|
|
73
|
-
def format_number(value)
|
|
74
|
-
formatted = super(value)
|
|
75
|
+
def format_number(value, type: nil)
|
|
76
|
+
formatted = super(value, type: type)
|
|
77
|
+
return formatted if type == :int || value.is_a?(Integer)
|
|
78
|
+
|
|
75
79
|
"#{formatted}f"
|
|
76
80
|
end
|
|
77
81
|
|
|
78
82
|
def emit_profile_func_call(node)
|
|
79
83
|
name = node.name.to_sym
|
|
80
|
-
return
|
|
81
|
-
|
|
84
|
+
return emit_c_vector_constructor(node) if vector_type?(name)
|
|
85
|
+
if name == :atan && node.args.length == 2
|
|
86
|
+
return emit_named_call("atan2f", node.args, expected_types: node.expected_arg_types)
|
|
87
|
+
end
|
|
88
|
+
if %i[distance cross].include?(name) && vector_type?(node.args.first&.type)
|
|
89
|
+
return emit_named_call("#{node.args.first.type}_#{name}", node.args,
|
|
90
|
+
expected_types: node.expected_arg_types)
|
|
91
|
+
end
|
|
92
|
+
if vector_math_call?(name, node)
|
|
93
|
+
return emit_named_call("#{node.args.first.type}_#{name}", node.args,
|
|
94
|
+
expected_types: node.expected_arg_types)
|
|
95
|
+
end
|
|
96
|
+
if vector_mix_call?(name, node)
|
|
97
|
+
return emit_named_call("mix_#{vector_suffix(node.args.first.type)}", node.args,
|
|
98
|
+
expected_types: node.expected_arg_types)
|
|
99
|
+
end
|
|
82
100
|
end
|
|
83
101
|
|
|
84
102
|
def emit_profile_binary_op(node)
|
|
85
|
-
return
|
|
103
|
+
return emit_float_modulo(node) if node.operator == "%" && node.type == :float
|
|
104
|
+
return unless profile.vector_ops.key?(node.operator)
|
|
105
|
+
|
|
106
|
+
emit_vector_binary_op(node)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def emit_unary_op(node)
|
|
110
|
+
if node.operator == "-" && vector_type?(node.operand.type)
|
|
111
|
+
return emit_named_call("#{node.operand.type}_mul_scalar", [node.operand, IR::Literal.new(-1.0, :float)])
|
|
112
|
+
end
|
|
86
113
|
|
|
87
|
-
|
|
114
|
+
super
|
|
88
115
|
end
|
|
89
116
|
|
|
90
117
|
def emit_bool_literal(node)
|
|
91
118
|
node.value ? "1" : "0"
|
|
92
119
|
end
|
|
93
120
|
|
|
121
|
+
def emit_field_access(node)
|
|
122
|
+
return super if node.receiver.type == :uniforms
|
|
123
|
+
|
|
124
|
+
field = node.field.to_s
|
|
125
|
+
if Builtins.single_component_field?(field)
|
|
126
|
+
component = Builtins::SWIZZLE_COMPONENTS.fetch(field)
|
|
127
|
+
return "#{emit(node.receiver)}.#{%w[x y z w].fetch(component)}"
|
|
128
|
+
end
|
|
129
|
+
return super unless Builtins.swizzle?(field)
|
|
130
|
+
|
|
131
|
+
indices = field.each_char.map { |component| Builtins::SWIZZLE_COMPONENTS.fetch(component) }
|
|
132
|
+
"#{node.receiver.type}_swizzle#{indices.length}(#{emit(node.receiver)}, #{indices.join(', ')})"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def emit_float_operand(node)
|
|
136
|
+
return emit(node) unless node.type == :int
|
|
137
|
+
|
|
138
|
+
"(float)(#{emit(node)})"
|
|
139
|
+
end
|
|
140
|
+
|
|
94
141
|
private
|
|
95
142
|
|
|
96
143
|
def vector_math_call?(name, node)
|
|
@@ -104,6 +151,55 @@ module RLSL
|
|
|
104
151
|
def vector_type?(type)
|
|
105
152
|
%i[vec2 vec3 vec4].include?(type)
|
|
106
153
|
end
|
|
154
|
+
|
|
155
|
+
def vector_suffix(type)
|
|
156
|
+
{ vec2: "v2", vec3: "v3", vec4: "v4" }.fetch(type)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def emit_float_modulo(node)
|
|
160
|
+
"rlsl_mod(#{emit_float_operand(node.left)}, #{emit_float_operand(node.right)})"
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def emit_vector_binary_op(node)
|
|
164
|
+
left_vector = vector_type?(node.left.type)
|
|
165
|
+
right_vector = vector_type?(node.right.type)
|
|
166
|
+
return unless left_vector || right_vector
|
|
167
|
+
|
|
168
|
+
vector_type = left_vector ? node.left.type : node.right.type
|
|
169
|
+
operation = profile.vector_ops.fetch(node.operator)
|
|
170
|
+
|
|
171
|
+
if left_vector && right_vector
|
|
172
|
+
suffix = %w[* /].include?(node.operator) ? "_components" : ""
|
|
173
|
+
return emit_named_call("#{vector_type}_#{operation}#{suffix}", [node.left, node.right])
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if left_vector
|
|
177
|
+
return emit_named_call("#{vector_type}_#{operation}_scalar", [node.left, node.right])
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
emit_named_call("#{vector_type}_scalar_#{operation}", [node.left, node.right])
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def emit_c_vector_constructor(node)
|
|
184
|
+
size = { vec2: 2, vec3: 3, vec4: 4 }.fetch(node.name.to_sym)
|
|
185
|
+
component_count = node.args.sum { |argument| vector_size(argument.type) || 1 }
|
|
186
|
+
component_count = size if node.args.length == 1 && !vector_type?(node.args.first.type)
|
|
187
|
+
|
|
188
|
+
unless component_count == size
|
|
189
|
+
raise TargetCapabilityError,
|
|
190
|
+
"#{node.name} constructor produces #{component_count} components on C, expected #{size}"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
return "#{node.name}_splat(#{emit(node.args.first)})" if node.args.length == 1 && !vector_type?(node.args.first.type)
|
|
194
|
+
return emit_named_call("#{node.name}_new", node.args) unless node.args.any? { |argument| vector_type?(argument.type) }
|
|
195
|
+
|
|
196
|
+
signature = node.args.map { |argument| vector_type?(argument.type) ? argument.type : :float }.join("_")
|
|
197
|
+
emit_named_call("#{node.name}_from_#{signature}", node.args)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def vector_size(type)
|
|
201
|
+
{ vec2: 2, vec3: 3, vec4: 4 }[type]
|
|
202
|
+
end
|
|
107
203
|
end
|
|
108
204
|
end
|
|
109
205
|
end
|
|
@@ -33,6 +33,54 @@ module RLSL
|
|
|
33
33
|
textureLod: "textureLod"
|
|
34
34
|
}
|
|
35
35
|
).freeze
|
|
36
|
+
|
|
37
|
+
protected
|
|
38
|
+
|
|
39
|
+
def function_qualifier
|
|
40
|
+
""
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def emit_binary_op(node)
|
|
44
|
+
if node.operator == "%" && (node.left.type != :int || node.right.type != :int)
|
|
45
|
+
return "mod(#{emit_float_operand(node.left)}, #{emit_float_operand(node.right)})"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
super
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def emit_result_struct(func_name, types)
|
|
52
|
+
fields = types.each_with_index.map { |type, index| "#{type_name(type)} v#{index};" }.join(" ")
|
|
53
|
+
"struct #{func_name}_result { #{fields} };\n"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def emit_field_access(node)
|
|
57
|
+
return node.field.to_s if node.receiver.type == :uniforms && node.type == :sampler2D
|
|
58
|
+
|
|
59
|
+
super
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def emit_texture_call(name, node)
|
|
63
|
+
return unless profile.texture_functions.key?(name) && node.args.length >= 2
|
|
64
|
+
|
|
65
|
+
args = [node.args[0], node.args[1], node.args[2] || IR::Literal.new(0.0, :float)]
|
|
66
|
+
emit_named_call("textureLod", args, expected_types: node.expected_arg_types)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def emit_func_call(node)
|
|
70
|
+
if node.name.to_sym == :atan2
|
|
71
|
+
return emit_named_call("atan", node.args, expected_types: node.expected_arg_types)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
super
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def emit_tuple_value(node)
|
|
78
|
+
expected_types = Array(current_return_type)
|
|
79
|
+
elements = node.elements.each_with_index.map do |element, index|
|
|
80
|
+
emit_typed_argument(element, expected_types[index])
|
|
81
|
+
end.join(", ")
|
|
82
|
+
"#{current_return_struct_name}(#{elements})"
|
|
83
|
+
end
|
|
36
84
|
end
|
|
37
85
|
end
|
|
38
86
|
end
|
|
@@ -41,7 +41,49 @@ module RLSL
|
|
|
41
41
|
|
|
42
42
|
texture = emit(node.args[0])
|
|
43
43
|
uv = emit(node.args[1])
|
|
44
|
-
|
|
44
|
+
if name == :textureLod
|
|
45
|
+
lod = emit_typed_argument(node.args[2], :float)
|
|
46
|
+
return "#{texture}.sample(rlsl_texture_sampler, #{uv}, level(#{lod}))"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
"#{texture}.sample(rlsl_texture_sampler, #{uv})"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def emit_binary_op(node)
|
|
53
|
+
if node.operator == "%" && node.type == :float
|
|
54
|
+
return "rlsl_mod(#{emit_float_operand(node.left)}, #{emit_float_operand(node.right)})"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def emit_func_call(node)
|
|
61
|
+
if node.name.to_sym == :mod
|
|
62
|
+
args = node.args.map { |argument| emit_float_operand(argument) }
|
|
63
|
+
return "rlsl_mod(#{args.join(', ')})"
|
|
64
|
+
end
|
|
65
|
+
if node.name.to_sym == :atan && node.args.length == 2
|
|
66
|
+
return emit_named_call("atan2", node.args, expected_types: node.expected_arg_types)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def emit_field_access(node)
|
|
73
|
+
return node.field.to_s if node.receiver.type == :uniforms && node.type == :sampler2D
|
|
74
|
+
|
|
75
|
+
code = super
|
|
76
|
+
return "(#{code} != 0)" if node.receiver.type == :uniforms && node.type == :bool
|
|
77
|
+
|
|
78
|
+
code
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def emit_tuple_value(node)
|
|
82
|
+
expected_types = Array(current_return_type)
|
|
83
|
+
elements = node.elements.each_with_index.map do |element, index|
|
|
84
|
+
emit_typed_argument(element, expected_types[index])
|
|
85
|
+
end.join(", ")
|
|
86
|
+
"#{current_return_struct_name}{#{elements}}"
|
|
45
87
|
end
|
|
46
88
|
end
|
|
47
89
|
end
|
|
@@ -19,26 +19,39 @@ module RLSL
|
|
|
19
19
|
name = node.name.to_sym
|
|
20
20
|
|
|
21
21
|
constructor_name = profile.vector_constructors[name] || profile.matrix_constructors[name]
|
|
22
|
-
|
|
22
|
+
if constructor_name
|
|
23
|
+
return emit_named_call(constructor_name, node.args, expected_types: Array.new(node.args.length, :float))
|
|
24
|
+
end
|
|
23
25
|
|
|
24
26
|
texture_call = emit_texture_call(name, node)
|
|
25
27
|
return texture_call if texture_call
|
|
26
28
|
|
|
27
29
|
math_function = profile.math_functions[name]
|
|
28
|
-
return emit_named_call(math_function, node.args) if math_function
|
|
30
|
+
return emit_named_call(math_function, node.args, expected_types: node.expected_arg_types) if math_function
|
|
29
31
|
|
|
30
|
-
emit_named_call(name, node.args, receiver: node.receiver)
|
|
32
|
+
emit_named_call(name, node.args, receiver: node.receiver, expected_types: node.expected_arg_types)
|
|
31
33
|
end
|
|
32
34
|
|
|
33
35
|
def emit_binary_op(node)
|
|
34
36
|
resolved_binary_op = emit_profile_binary_op(node)
|
|
35
37
|
return resolved_binary_op if resolved_binary_op
|
|
38
|
+
return emit_promoted_binary_op(node) if needs_float_promotion?(node)
|
|
36
39
|
|
|
37
|
-
left = emit_with_precedence(node.left, node.operator)
|
|
38
|
-
right = emit_with_precedence(node.right, node.operator)
|
|
40
|
+
left = emit_with_precedence(node.left, node.operator, side: :left)
|
|
41
|
+
right = emit_with_precedence(node.right, node.operator, side: :right)
|
|
39
42
|
"#{left} #{node.operator} #{right}"
|
|
40
43
|
end
|
|
41
44
|
|
|
45
|
+
def emit_ternary(node)
|
|
46
|
+
then_expr = emit_typed_argument(node.then_expr, node.type)
|
|
47
|
+
else_expr = emit_typed_argument(node.else_expr, node.type)
|
|
48
|
+
"(#{emit(node.condition)} ? #{then_expr} : #{else_expr})"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def emit_assignment(node)
|
|
52
|
+
"#{emit(node.target)} = #{emit_typed_argument(node.value, node.target.type)}"
|
|
53
|
+
end
|
|
54
|
+
|
|
42
55
|
def default_type_name
|
|
43
56
|
profile.default_type_name
|
|
44
57
|
end
|
|
@@ -46,16 +59,50 @@ module RLSL
|
|
|
46
59
|
def emit_texture_call(name, node)
|
|
47
60
|
return unless profile.texture_functions.key?(name)
|
|
48
61
|
|
|
49
|
-
emit_named_call(profile.texture_functions[name], node.args)
|
|
62
|
+
emit_named_call(profile.texture_functions[name], node.args, expected_types: node.expected_arg_types)
|
|
50
63
|
end
|
|
51
64
|
|
|
52
|
-
def emit_named_call(name, args, receiver: nil)
|
|
65
|
+
def emit_named_call(name, args, receiver: nil, expected_types: [])
|
|
53
66
|
rendered_args = []
|
|
54
|
-
rendered_args <<
|
|
55
|
-
|
|
67
|
+
rendered_args << emit_typed_argument(receiver, expected_types.first) if receiver
|
|
68
|
+
offset = receiver ? 1 : 0
|
|
69
|
+
rendered_args.concat(args.each_with_index.map do |arg, index|
|
|
70
|
+
emit_typed_argument(arg, expected_types[index + offset])
|
|
71
|
+
end)
|
|
56
72
|
"#{name}(#{rendered_args.join(', ')})"
|
|
57
73
|
end
|
|
58
74
|
|
|
75
|
+
def emit_typed_argument(node, expected_type)
|
|
76
|
+
return emit_float_operand(node) if expected_type == :float
|
|
77
|
+
|
|
78
|
+
emit(node)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def needs_float_promotion?(node)
|
|
82
|
+
types = [node.left.type, node.right.type]
|
|
83
|
+
return true if node.operator == "/" && types.all?(:int)
|
|
84
|
+
|
|
85
|
+
types.include?(:int) && types.any? { |type| type == :float || Builtins.vector_type?(type) || Builtins.matrix_type?(type) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def emit_promoted_binary_op(node)
|
|
89
|
+
left = emit_promoted_operand(node.left, node.operator, :left)
|
|
90
|
+
right = emit_promoted_operand(node.right, node.operator, :right)
|
|
91
|
+
"#{left} #{node.operator} #{right}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def emit_float_operand(node)
|
|
95
|
+
return emit(node) unless node.type == :int
|
|
96
|
+
|
|
97
|
+
"#{type_name(:float)}(#{emit(node)})"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def emit_promoted_operand(node, operator, side)
|
|
101
|
+
return emit_float_operand(node) if node.type == :int
|
|
102
|
+
|
|
103
|
+
emit_with_precedence(node, operator, side: side)
|
|
104
|
+
end
|
|
105
|
+
|
|
59
106
|
def emit_profile_call(node)
|
|
60
107
|
return unless profile.call_resolver
|
|
61
108
|
|