rlsl 0.1.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +18 -1
- data/lib/rlsl/base_translator/call_parser.rb +68 -0
- data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
- data/lib/rlsl/base_translator/code_scanner.rb +102 -0
- data/lib/rlsl/base_translator.rb +159 -63
- data/lib/rlsl/code_generator/math_prelude.rb +79 -0
- data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +97 -0
- data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
- data/lib/rlsl/code_generator/template_context.rb +41 -0
- data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
- data/lib/rlsl/code_generator.rb +26 -201
- data/lib/rlsl/compiled_shader.rb +4 -12
- data/lib/rlsl/function_context.rb +31 -14
- data/lib/rlsl/glsl/translator.rb +19 -38
- data/lib/rlsl/msl/shader.rb +8 -38
- data/lib/rlsl/msl/translator.rb +19 -36
- data/lib/rlsl/msl/uniform_buffer_packer.rb +68 -0
- data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +96 -0
- data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +79 -0
- data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +168 -0
- data/lib/rlsl/prism/ast_visitor/scope_context.rb +44 -0
- data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
- data/lib/rlsl/prism/ast_visitor.rb +54 -298
- data/lib/rlsl/prism/builtins/function_registry.rb +114 -0
- data/lib/rlsl/prism/builtins/operator_rules.rb +99 -0
- data/lib/rlsl/prism/builtins/swizzle_rules.rb +38 -0
- data/lib/rlsl/prism/builtins.rb +31 -148
- data/lib/rlsl/prism/compilation_unit.rb +7 -0
- data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +83 -0
- data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +104 -0
- data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +92 -0
- data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +89 -0
- data/lib/rlsl/prism/emitters/base_emitter.rb +68 -423
- data/lib/rlsl/prism/emitters/c_emitter.rb +78 -121
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +30 -65
- data/lib/rlsl/prism/emitters/msl_emitter.rb +35 -62
- data/lib/rlsl/prism/emitters/target_emitter.rb +77 -0
- data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +65 -61
- data/lib/rlsl/prism/ir/control_flow.rb +83 -0
- data/lib/rlsl/prism/ir/definitions.rb +67 -0
- data/lib/rlsl/prism/ir/expressions.rb +197 -0
- data/lib/rlsl/prism/ir/node.rb +21 -0
- data/lib/rlsl/prism/ir/nodes.rb +4 -371
- data/lib/rlsl/prism/ir/traversal.rb +62 -0
- data/lib/rlsl/prism/source_extractor/block_locator.rb +52 -0
- data/lib/rlsl/prism/source_extractor.rb +14 -133
- data/lib/rlsl/prism/source_unit/parser.rb +78 -0
- data/lib/rlsl/prism/source_unit.rb +42 -0
- data/lib/rlsl/prism/target_capability_validator.rb +85 -0
- data/lib/rlsl/prism/transpiler.rb +63 -60
- data/lib/rlsl/prism/type_inference/call_type_resolver.rb +35 -0
- data/lib/rlsl/prism/type_inference/call_validator.rb +71 -0
- data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +80 -0
- data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +66 -0
- data/lib/rlsl/prism/type_inference/definition_inferer.rb +41 -0
- data/lib/rlsl/prism/type_inference/expression_inferer.rb +92 -0
- data/lib/rlsl/prism/type_inference/field_type_resolver.rb +17 -0
- data/lib/rlsl/prism/type_inference/inferer_registry.rb +38 -0
- data/lib/rlsl/prism/type_inference/scope_stack.rb +47 -0
- data/lib/rlsl/prism/type_inference/type_environment.rb +112 -0
- data/lib/rlsl/prism/type_inference/type_shapes.rb +33 -0
- data/lib/rlsl/prism/type_inference.rb +114 -248
- data/lib/rlsl/runtime_shader.rb +47 -0
- data/lib/rlsl/shader_builder/build_service.rb +77 -0
- data/lib/rlsl/shader_builder/native_extension_compiler.rb +71 -0
- data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
- data/lib/rlsl/shader_builder/source_resolver.rb +91 -0
- data/lib/rlsl/shader_builder.rb +22 -113
- data/lib/rlsl/types/catalog.rb +47 -0
- data/lib/rlsl/types/target_resolver.rb +15 -0
- data/lib/rlsl/types/type_spec.rb +167 -0
- data/lib/rlsl/types/value_normalizer.rb +81 -0
- data/lib/rlsl/types.rb +11 -29
- data/lib/rlsl/uniform_context.rb +6 -12
- data/lib/rlsl/version.rb +1 -1
- data/lib/rlsl/wgsl/translator.rb +23 -39
- data/lib/rlsl.rb +14 -12
- metadata +55 -16
|
@@ -3,17 +3,38 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
require "set"
|
|
5
5
|
|
|
6
|
+
require_relative "ast_visitor/visitor_registry"
|
|
7
|
+
require_relative "ast_visitor/scope_context"
|
|
8
|
+
require_relative "ast_visitor/expression_visiting"
|
|
9
|
+
require_relative "ast_visitor/control_flow_visiting"
|
|
10
|
+
require_relative "ast_visitor/definition_visiting"
|
|
11
|
+
|
|
6
12
|
module RLSL
|
|
7
13
|
module Prism
|
|
14
|
+
class UnsupportedSyntaxError < StandardError; end
|
|
15
|
+
|
|
8
16
|
class ASTVisitor
|
|
9
17
|
BINARY_OPERATORS = %w[+ - * / % == != < > <= >= && ||].freeze
|
|
10
18
|
UNARY_OPERATORS = %w[- !].freeze
|
|
19
|
+
TRANSPARENT_NODES = VisitorRegistry::TRANSPARENT_NODES
|
|
20
|
+
NODE_VISITORS = VisitorRegistry.build(
|
|
21
|
+
{}.tap do |visitors|
|
|
22
|
+
visitors[::Prism::ProgramNode] = :visit_program if defined?(::Prism::ProgramNode)
|
|
23
|
+
visitors[::Prism::StatementsNode] = :visit_statements if defined?(::Prism::StatementsNode)
|
|
24
|
+
end,
|
|
25
|
+
ExpressionVisiting::VISITORS,
|
|
26
|
+
ControlFlowVisiting::VISITORS,
|
|
27
|
+
DefinitionVisiting::VISITORS
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
include ExpressionVisiting
|
|
31
|
+
include ControlFlowVisiting
|
|
32
|
+
include DefinitionVisiting
|
|
11
33
|
|
|
12
34
|
def initialize(context = {})
|
|
13
35
|
@context = context
|
|
14
36
|
@uniforms = context[:uniforms] || {}
|
|
15
|
-
@
|
|
16
|
-
@declared_vars = Set.new
|
|
37
|
+
@scope_context = ScopeContext.new(params: context[:params] || [])
|
|
17
38
|
end
|
|
18
39
|
|
|
19
40
|
def parse(source)
|
|
@@ -31,24 +52,16 @@ module RLSL
|
|
|
31
52
|
def visit(node)
|
|
32
53
|
return nil if node.nil?
|
|
33
54
|
|
|
34
|
-
method_name =
|
|
35
|
-
|
|
36
|
-
send(method_name, node)
|
|
37
|
-
else
|
|
38
|
-
visit_default(node)
|
|
39
|
-
end
|
|
40
|
-
end
|
|
55
|
+
method_name = NODE_VISITORS[node.class]
|
|
56
|
+
return send(method_name, node) if method_name
|
|
41
57
|
|
|
42
|
-
|
|
58
|
+
raise UnsupportedSyntaxError, "Unsupported Prism node: #{node.class}" unless transparent_node?(node)
|
|
43
59
|
|
|
44
|
-
|
|
45
|
-
node.class.name.split("::").last
|
|
46
|
-
.gsub(/Node$/, "")
|
|
47
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
|
48
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
|
49
|
-
.downcase
|
|
60
|
+
visit_default(node)
|
|
50
61
|
end
|
|
51
62
|
|
|
63
|
+
private
|
|
64
|
+
|
|
52
65
|
def visit_default(node)
|
|
53
66
|
children = []
|
|
54
67
|
node.child_nodes.compact.each do |child|
|
|
@@ -58,6 +71,10 @@ module RLSL
|
|
|
58
71
|
children.length == 1 ? children.first : children
|
|
59
72
|
end
|
|
60
73
|
|
|
74
|
+
def transparent_node?(node)
|
|
75
|
+
TRANSPARENT_NODES.include?(node.class)
|
|
76
|
+
end
|
|
77
|
+
|
|
61
78
|
def visit_program(node)
|
|
62
79
|
visit(node.statements)
|
|
63
80
|
end
|
|
@@ -67,304 +84,43 @@ module RLSL
|
|
|
67
84
|
IR::Block.new(statements)
|
|
68
85
|
end
|
|
69
86
|
|
|
70
|
-
def
|
|
71
|
-
|
|
72
|
-
node.parameters.parameters&.requireds&.each do |param|
|
|
73
|
-
@params.add(param.name.to_sym)
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
visit(node.body)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def visit_lambda(node)
|
|
81
|
-
visit_block(node)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
def visit_local_variable_write(node)
|
|
85
|
-
name = node.name.to_sym
|
|
86
|
-
value = visit(node.value)
|
|
87
|
-
|
|
88
|
-
if @declared_vars.include?(name) || @params.include?(name)
|
|
89
|
-
IR::Assignment.new(IR::VarRef.new(name), value)
|
|
90
|
-
else
|
|
91
|
-
@declared_vars.add(name)
|
|
92
|
-
IR::VarDecl.new(name, value)
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def visit_local_variable_read(node)
|
|
97
|
-
name = node.name.to_sym
|
|
98
|
-
type = infer_param_type(name)
|
|
99
|
-
IR::VarRef.new(name, type)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def visit_integer(node)
|
|
103
|
-
IR::Literal.new(node.value.to_f, :float)
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def visit_float(node)
|
|
107
|
-
IR::Literal.new(node.value, :float)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def visit_rational(node)
|
|
111
|
-
IR::Literal.new(node.value.to_f, :float)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def visit_true(node)
|
|
115
|
-
IR::BoolLiteral.new(true)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def visit_false(node)
|
|
119
|
-
IR::BoolLiteral.new(false)
|
|
87
|
+
def visit_with_scoped_vars(node, params: [])
|
|
88
|
+
@scope_context.with_scope(params: params) { visit(node) }
|
|
120
89
|
end
|
|
121
90
|
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def visit_call(node)
|
|
131
|
-
method_name = node.name.to_s
|
|
132
|
-
receiver = visit(node.receiver) if node.receiver
|
|
133
|
-
args = node.arguments&.arguments&.map { |arg| visit(arg) } || []
|
|
134
|
-
|
|
135
|
-
if !receiver && args.empty? && @params.include?(method_name.to_sym)
|
|
136
|
-
type = infer_param_type(method_name.to_sym)
|
|
137
|
-
return IR::VarRef.new(method_name.to_sym, type)
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
if receiver && args.empty? && !node.arguments
|
|
141
|
-
if Builtins.single_component_field?(method_name)
|
|
142
|
-
return IR::FieldAccess.new(receiver, method_name, :float)
|
|
143
|
-
elsif Builtins.swizzle?(method_name)
|
|
144
|
-
type = Builtins.swizzle_type(method_name)
|
|
145
|
-
return IR::Swizzle.new(receiver, method_name, type)
|
|
146
|
-
else
|
|
147
|
-
return IR::FieldAccess.new(receiver, method_name)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
if BINARY_OPERATORS.include?(method_name) && receiver && args.length == 1
|
|
152
|
-
return IR::BinaryOp.new(method_name, receiver, args.first)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
if method_name == "-@" && receiver
|
|
156
|
-
return IR::UnaryOp.new("-", receiver)
|
|
157
|
-
end
|
|
158
|
-
if method_name == "!" && args.length == 1
|
|
159
|
-
return IR::UnaryOp.new("!", args.first)
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
if method_name == "[]" && receiver && args.length == 1
|
|
163
|
-
return IR::ArrayIndex.new(receiver, args.first)
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
IR::FuncCall.new(method_name.to_sym, args, receiver)
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
def visit_if(node)
|
|
170
|
-
condition = visit(node.predicate)
|
|
171
|
-
then_branch = visit_with_scoped_vars(node.statements)
|
|
172
|
-
else_branch = node.subsequent ? visit_with_scoped_vars(node.subsequent) : nil
|
|
173
|
-
|
|
174
|
-
IR::IfStatement.new(condition, then_branch, else_branch)
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
def visit_with_scoped_vars(node)
|
|
178
|
-
saved_vars = @declared_vars.dup
|
|
179
|
-
result = visit(node)
|
|
180
|
-
@declared_vars = saved_vars
|
|
181
|
-
result
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
def visit_else(node)
|
|
185
|
-
visit(node.statements)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def visit_elsif(node)
|
|
189
|
-
visit_if(node)
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def visit_if_node(node)
|
|
193
|
-
visit_if(node)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def visit_unless(node)
|
|
197
|
-
condition = IR::UnaryOp.new("!", visit(node.predicate))
|
|
198
|
-
then_branch = visit(node.statements)
|
|
199
|
-
else_branch = node.else_clause ? visit(node.else_clause) : nil
|
|
200
|
-
|
|
201
|
-
IR::IfStatement.new(condition, then_branch, else_branch)
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def visit_return(node)
|
|
205
|
-
expr = node.arguments ? visit(node.arguments.arguments.first) : nil
|
|
206
|
-
IR::Return.new(expr)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
def visit_range(node)
|
|
210
|
-
[visit(node.left), visit(node.right)]
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
def visit_for(node)
|
|
214
|
-
var_name = node.index.name.to_sym
|
|
215
|
-
range = visit(node.collection)
|
|
216
|
-
body = visit(node.statements)
|
|
217
|
-
|
|
218
|
-
IR::ForLoop.new(var_name, range[0], range[1], body)
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def visit_call_with_block(node)
|
|
222
|
-
call_node = node
|
|
223
|
-
method_name = call_node.name.to_s
|
|
224
|
-
|
|
225
|
-
if method_name == "times" && call_node.receiver
|
|
226
|
-
count = visit(call_node.receiver)
|
|
227
|
-
block = visit(call_node.block)
|
|
228
|
-
|
|
229
|
-
var_name = :i
|
|
230
|
-
if call_node.block&.parameters&.parameters&.requireds&.any?
|
|
231
|
-
var_name = call_node.block.parameters.parameters.requireds.first.name.to_sym
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
IR::ForLoop.new(var_name, IR::Literal.new(0, :int), count, block)
|
|
235
|
-
else
|
|
236
|
-
visit_call(node)
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def visit_and(node)
|
|
241
|
-
left = visit(node.left)
|
|
242
|
-
right = visit(node.right)
|
|
243
|
-
IR::BinaryOp.new("&&", left, right, :bool)
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
def visit_or(node)
|
|
247
|
-
left = visit(node.left)
|
|
248
|
-
right = visit(node.right)
|
|
249
|
-
IR::BinaryOp.new("||", left, right, :bool)
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def visit_not(node)
|
|
253
|
-
operand = visit(node.expression)
|
|
254
|
-
IR::UnaryOp.new("!", operand, :bool)
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
def visit_while(node)
|
|
258
|
-
condition = visit(node.predicate)
|
|
259
|
-
body = visit(node.statements)
|
|
260
|
-
IR::WhileLoop.new(condition, body)
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
def visit_break(node)
|
|
264
|
-
IR::Break.new
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
def visit_constant_read(node)
|
|
268
|
-
name = node.name.to_s
|
|
269
|
-
if %w[PI TAU].include?(name)
|
|
270
|
-
IR::Constant.new(name.to_sym, :float)
|
|
91
|
+
def infer_param_type(name)
|
|
92
|
+
case name
|
|
93
|
+
when :frag_coord, :resolution
|
|
94
|
+
:vec2
|
|
95
|
+
when :u
|
|
96
|
+
:uniforms
|
|
271
97
|
else
|
|
272
|
-
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
|
|
276
|
-
def visit_def(node)
|
|
277
|
-
name = node.name.to_sym
|
|
278
|
-
params = []
|
|
279
|
-
|
|
280
|
-
if node.parameters
|
|
281
|
-
node.parameters.requireds&.each do |param|
|
|
282
|
-
params << param.name.to_sym
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
saved_params = @params.dup
|
|
287
|
-
saved_declared_vars = @declared_vars.dup
|
|
288
|
-
@declared_vars = Set.new
|
|
289
|
-
params.each { |p| @params.add(p) }
|
|
290
|
-
|
|
291
|
-
body = visit(node.body)
|
|
292
|
-
|
|
293
|
-
@params = saved_params
|
|
294
|
-
@declared_vars = saved_declared_vars
|
|
295
|
-
|
|
296
|
-
IR::FunctionDefinition.new(name, params, body)
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
def visit_array(node)
|
|
300
|
-
elements = node.elements.map { |elem| visit(elem) }
|
|
301
|
-
IR::ArrayLiteral.new(elements)
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def visit_index(node)
|
|
305
|
-
array = visit(node.receiver)
|
|
306
|
-
index = visit(node.arguments.arguments.first)
|
|
307
|
-
IR::ArrayIndex.new(array, index)
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
def visit_constant_path(node)
|
|
311
|
-
path_parts = []
|
|
312
|
-
current = node
|
|
313
|
-
while current.is_a?(::Prism::ConstantPathNode)
|
|
314
|
-
path_parts.unshift(current.name.to_s)
|
|
315
|
-
current = current.parent
|
|
98
|
+
nil
|
|
316
99
|
end
|
|
317
|
-
path_parts.unshift(current.name.to_s) if current.respond_to?(:name)
|
|
318
|
-
|
|
319
|
-
full_name = path_parts.join("_")
|
|
320
|
-
IR::VarRef.new(full_name.to_sym)
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
def visit_global_variable_read(node)
|
|
324
|
-
name = node.name.to_s.sub(/^\$/, "").to_sym
|
|
325
|
-
IR::VarRef.new(name)
|
|
326
100
|
end
|
|
327
101
|
|
|
328
|
-
def
|
|
329
|
-
|
|
330
|
-
value = visit(node.value)
|
|
102
|
+
def extract_required_params(node)
|
|
103
|
+
return [] unless node
|
|
331
104
|
|
|
332
|
-
|
|
105
|
+
node.requireds&.map { |param| param.name.to_sym } || []
|
|
333
106
|
end
|
|
334
107
|
|
|
335
|
-
def
|
|
336
|
-
|
|
337
|
-
value = visit(node.value)
|
|
108
|
+
def extract_block_params(node)
|
|
109
|
+
return [] unless node&.parameters
|
|
338
110
|
|
|
339
|
-
|
|
111
|
+
extract_required_params(node.parameters.parameters)
|
|
340
112
|
end
|
|
341
113
|
|
|
342
|
-
def
|
|
343
|
-
|
|
344
|
-
name = target.name.to_sym
|
|
345
|
-
@declared_vars.add(name)
|
|
346
|
-
IR::VarRef.new(name)
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
value = visit(node.value)
|
|
350
|
-
IR::MultipleAssignment.new(targets, value)
|
|
114
|
+
def parameter_reference?(name)
|
|
115
|
+
@scope_context.parameter?(name)
|
|
351
116
|
end
|
|
352
117
|
|
|
353
|
-
def
|
|
354
|
-
|
|
355
|
-
@declared_vars.add(name)
|
|
356
|
-
IR::VarRef.new(name)
|
|
118
|
+
def known_variable?(name)
|
|
119
|
+
@scope_context.known_variable?(name)
|
|
357
120
|
end
|
|
358
121
|
|
|
359
|
-
def
|
|
360
|
-
|
|
361
|
-
when :frag_coord, :resolution
|
|
362
|
-
:vec2
|
|
363
|
-
when :u
|
|
364
|
-
:uniforms
|
|
365
|
-
else
|
|
366
|
-
nil
|
|
367
|
-
end
|
|
122
|
+
def declare_variable(name)
|
|
123
|
+
@scope_context.declare(name)
|
|
368
124
|
end
|
|
369
125
|
end
|
|
370
126
|
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module Prism
|
|
5
|
+
module Builtins
|
|
6
|
+
module FunctionRegistry
|
|
7
|
+
ALL_TARGETS = %i[c glsl wgsl msl].freeze
|
|
8
|
+
META_TYPES = %i[any same first second third].freeze
|
|
9
|
+
|
|
10
|
+
FUNCTIONS = {
|
|
11
|
+
vec2: { args: %i[any any], returns: :vec2, variadic: true, min_args: 1 },
|
|
12
|
+
vec3: { args: %i[any any any], returns: :vec3, variadic: true, min_args: 1 },
|
|
13
|
+
vec4: { args: %i[any any any any], returns: :vec4, variadic: true, min_args: 1 },
|
|
14
|
+
|
|
15
|
+
mat2: { args: %i[any any any any], returns: :mat2, variadic: true, min_args: 1 },
|
|
16
|
+
mat3: { args: %i[any any any any any any any any any], returns: :mat3, variadic: true, min_args: 1 },
|
|
17
|
+
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 },
|
|
18
|
+
|
|
19
|
+
sin: { args: [:float], returns: :float },
|
|
20
|
+
cos: { args: [:float], returns: :float },
|
|
21
|
+
tan: { args: [:float], returns: :float },
|
|
22
|
+
asin: { args: [:float], returns: :float },
|
|
23
|
+
acos: { args: [:float], returns: :float },
|
|
24
|
+
atan: { args: %i[float float], returns: :float, variadic: true, min_args: 1 },
|
|
25
|
+
atan2: { args: %i[float float], returns: :float },
|
|
26
|
+
|
|
27
|
+
pow: { args: %i[float float], returns: :float },
|
|
28
|
+
exp: { args: [:float], returns: :float },
|
|
29
|
+
log: { args: [:float], returns: :float },
|
|
30
|
+
sqrt: { args: [:any], returns: :same },
|
|
31
|
+
|
|
32
|
+
abs: { args: [:any], returns: :same },
|
|
33
|
+
sign: { args: [:any], returns: :same },
|
|
34
|
+
floor: { args: [:any], returns: :same },
|
|
35
|
+
ceil: { args: [:any], returns: :same },
|
|
36
|
+
fract: { args: [:any], returns: :same },
|
|
37
|
+
mod: { args: %i[any float], returns: :first },
|
|
38
|
+
min: { args: %i[any any], returns: :first },
|
|
39
|
+
max: { args: %i[any any], returns: :first },
|
|
40
|
+
clamp: { args: %i[any any any], returns: :first },
|
|
41
|
+
mix: { args: %i[any any float], returns: :first },
|
|
42
|
+
step: { args: %i[float any], returns: :second },
|
|
43
|
+
smoothstep: { args: %i[float float any], returns: :third },
|
|
44
|
+
|
|
45
|
+
length: { args: [:any], returns: :float },
|
|
46
|
+
distance: { args: %i[any any], returns: :float },
|
|
47
|
+
dot: { args: %i[any any], returns: :float },
|
|
48
|
+
cross: { args: %i[vec3 vec3], returns: :vec3 },
|
|
49
|
+
normalize: { args: [:any], returns: :same },
|
|
50
|
+
reflect: { args: %i[any any], returns: :first },
|
|
51
|
+
refract: { args: %i[any any float], returns: :first },
|
|
52
|
+
|
|
53
|
+
hash21: { args: [:vec2], returns: :float },
|
|
54
|
+
hash22: { args: [:vec2], returns: :vec2 },
|
|
55
|
+
|
|
56
|
+
lessThan: { args: %i[any any], returns: :bool },
|
|
57
|
+
lessThanEqual: { args: %i[any any], returns: :bool },
|
|
58
|
+
greaterThan: { args: %i[any any], returns: :bool },
|
|
59
|
+
greaterThanEqual: { args: %i[any any], returns: :bool },
|
|
60
|
+
equal: { args: %i[any any], returns: :bool },
|
|
61
|
+
notEqual: { args: %i[any any], returns: :bool },
|
|
62
|
+
|
|
63
|
+
inverse: { args: [:any], returns: :same, targets: %i[glsl wgsl msl] },
|
|
64
|
+
transpose: { args: [:any], returns: :same, targets: %i[glsl wgsl msl] },
|
|
65
|
+
determinant: { args: [:any], returns: :float, targets: %i[glsl wgsl msl] },
|
|
66
|
+
|
|
67
|
+
texture2D: { args: %i[sampler2D vec2], returns: :vec4 },
|
|
68
|
+
texture: { args: %i[sampler2D vec2], returns: :vec4 },
|
|
69
|
+
textureLod: { args: %i[sampler2D vec2 float], returns: :vec4 }
|
|
70
|
+
}.freeze
|
|
71
|
+
|
|
72
|
+
module_function
|
|
73
|
+
|
|
74
|
+
def function?(name)
|
|
75
|
+
FUNCTIONS.key?(name.to_sym)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def function_signature(name)
|
|
79
|
+
FUNCTIONS[name.to_sym]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def supported_on_target?(name, target)
|
|
83
|
+
signature = function_signature(name)
|
|
84
|
+
return false unless signature
|
|
85
|
+
|
|
86
|
+
Array(signature[:targets] || ALL_TARGETS).include?(target.to_sym)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def explicit_types(name)
|
|
90
|
+
signature = function_signature(name)
|
|
91
|
+
return [] unless signature
|
|
92
|
+
|
|
93
|
+
([signature[:returns]] + Array(signature[:args])).filter_map do |type|
|
|
94
|
+
type if explicit_type?(type)
|
|
95
|
+
end.uniq
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def resolve_return_type(rule, arg_types)
|
|
99
|
+
case rule
|
|
100
|
+
when :same then arg_types.first
|
|
101
|
+
when :first then arg_types.first
|
|
102
|
+
when :second then arg_types[1]
|
|
103
|
+
when :third then arg_types[2]
|
|
104
|
+
when Symbol then rule
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def explicit_type?(type)
|
|
109
|
+
type.is_a?(Symbol) && !META_TYPES.include?(type)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
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
|
+
|
|
43
|
+
case op_kind
|
|
44
|
+
when :comparison, :logical
|
|
45
|
+
:bool
|
|
46
|
+
when :arithmetic
|
|
47
|
+
if matrix_type?(left_type) && vector_type?(right_type)
|
|
48
|
+
matrix_vector_result(left_type)
|
|
49
|
+
elsif vector_type?(left_type) && matrix_type?(right_type)
|
|
50
|
+
matrix_vector_result(right_type)
|
|
51
|
+
elsif matrix_type?(left_type) && matrix_type?(right_type)
|
|
52
|
+
left_type
|
|
53
|
+
elsif matrix_type?(left_type) && scalar_type?(right_type)
|
|
54
|
+
left_type
|
|
55
|
+
elsif scalar_type?(left_type) && matrix_type?(right_type)
|
|
56
|
+
right_type
|
|
57
|
+
elsif vector_type?(left_type) && vector_type?(right_type)
|
|
58
|
+
left_type
|
|
59
|
+
elsif vector_type?(left_type) && scalar_type?(right_type)
|
|
60
|
+
left_type
|
|
61
|
+
elsif scalar_type?(left_type) && vector_type?(right_type)
|
|
62
|
+
right_type
|
|
63
|
+
else
|
|
64
|
+
scalar_arithmetic_result_type(op, left_type, right_type)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def vector_type?(type)
|
|
70
|
+
%i[vec2 vec3 vec4].include?(type)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def matrix_type?(type)
|
|
74
|
+
%i[mat2 mat3 mat4].include?(type)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def scalar_type?(type)
|
|
78
|
+
%i[float int].include?(type)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def scalar_arithmetic_result_type(op, left_type, right_type)
|
|
82
|
+
return :float unless scalar_type?(left_type) && scalar_type?(right_type)
|
|
83
|
+
return :float if op.to_s == "/"
|
|
84
|
+
return :int if left_type == :int && right_type == :int
|
|
85
|
+
|
|
86
|
+
:float
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def matrix_vector_result(matrix_type)
|
|
90
|
+
case matrix_type
|
|
91
|
+
when :mat2 then :vec2
|
|
92
|
+
when :mat3 then :vec3
|
|
93
|
+
when :mat4 then :vec4
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
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[xyzwrgba]{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
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|