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.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +13 -2
- data/README.md +101 -26
- data/Rakefile +7 -0
- data/lib/rlsl/base_translator/call_parser.rb +79 -0
- data/lib/rlsl/base_translator/code_rewriter.rb +107 -0
- data/lib/rlsl/base_translator/code_scanner.rb +140 -0
- data/lib/rlsl/base_translator.rb +182 -64
- data/lib/rlsl/code_generator/math_prelude.rb +172 -0
- data/lib/rlsl/code_generator/ruby_wrapper_generator.rb +137 -0
- data/lib/rlsl/code_generator/shader_function_generator.rb +19 -0
- data/lib/rlsl/code_generator/template_context.rb +44 -0
- data/lib/rlsl/code_generator/uniform_struct_generator.rb +29 -0
- data/lib/rlsl/code_generator.rb +30 -202
- data/lib/rlsl/compiled_shader.rb +5 -13
- data/lib/rlsl/errors.rb +29 -0
- data/lib/rlsl/function_context.rb +31 -14
- data/lib/rlsl/glsl/translator.rb +35 -41
- data/lib/rlsl/msl/shader.rb +34 -46
- data/lib/rlsl/msl/translator.rb +38 -34
- data/lib/rlsl/msl/uniform_buffer_packer.rb +72 -0
- data/lib/rlsl/prism/ast_visitor/control_flow_visiting.rb +137 -0
- data/lib/rlsl/prism/ast_visitor/definition_visiting.rb +92 -0
- data/lib/rlsl/prism/ast_visitor/expression_visiting.rb +172 -0
- data/lib/rlsl/prism/ast_visitor/scope_context.rb +48 -0
- data/lib/rlsl/prism/ast_visitor/visitor_registry.rb +21 -0
- data/lib/rlsl/prism/ast_visitor.rb +100 -286
- data/lib/rlsl/prism/builtins/function_registry.rb +131 -0
- data/lib/rlsl/prism/builtins/operator_rules.rb +123 -0
- data/lib/rlsl/prism/builtins/swizzle_rules.rb +47 -0
- data/lib/rlsl/prism/builtins.rb +39 -148
- data/lib/rlsl/prism/compilation_unit.rb +7 -0
- data/lib/rlsl/prism/emitters/base_emitter/control_flow_emission.rb +126 -0
- data/lib/rlsl/prism/emitters/base_emitter/definition_emission.rb +134 -0
- data/lib/rlsl/prism/emitters/base_emitter/expression_emission.rb +108 -0
- data/lib/rlsl/prism/emitters/base_emitter/statement_emission.rb +95 -0
- data/lib/rlsl/prism/emitters/base_emitter.rb +120 -414
- data/lib/rlsl/prism/emitters/c_emitter.rb +165 -112
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +63 -50
- data/lib/rlsl/prism/emitters/msl_emitter.rb +67 -52
- data/lib/rlsl/prism/emitters/target_emitter.rb +124 -0
- data/lib/rlsl/prism/emitters/target_profile.rb +34 -0
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +217 -58
- data/lib/rlsl/prism/errors.rb +9 -0
- data/lib/rlsl/prism/ir/control_flow.rb +85 -0
- data/lib/rlsl/prism/ir/definitions.rb +82 -0
- data/lib/rlsl/prism/ir/expressions.rb +201 -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 +66 -0
- 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 +50 -0
- data/lib/rlsl/prism/source_extractor.rb +19 -137
- data/lib/rlsl/prism/source_unit/parser.rb +88 -0
- data/lib/rlsl/prism/source_unit.rb +42 -0
- data/lib/rlsl/prism/target_capability_validator.rb +110 -0
- data/lib/rlsl/prism/transpiler.rb +99 -59
- data/lib/rlsl/prism/type_inference/call_type_resolver.rb +59 -0
- data/lib/rlsl/prism/type_inference/call_validator.rb +75 -0
- data/lib/rlsl/prism/type_inference/collection_type_resolver.rb +106 -0
- data/lib/rlsl/prism/type_inference/control_flow_inferer.rb +147 -0
- data/lib/rlsl/prism/type_inference/definition_inferer.rb +56 -0
- data/lib/rlsl/prism/type_inference/expression_inferer.rb +96 -0
- data/lib/rlsl/prism/type_inference/field_type_resolver.rb +38 -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 +120 -249
- data/lib/rlsl/runtime_shader.rb +47 -0
- data/lib/rlsl/shader_builder/build_service.rb +104 -0
- data/lib/rlsl/shader_builder/native_extension_compiler.rb +97 -0
- data/lib/rlsl/shader_builder/shader_definition.rb +68 -0
- data/lib/rlsl/shader_builder/source_resolver.rb +109 -0
- data/lib/rlsl/shader_builder.rb +60 -111
- data/lib/rlsl/shader_name.rb +18 -0
- 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 +86 -0
- data/lib/rlsl/types.rb +9 -31
- data/lib/rlsl/uniform_context.rb +22 -11
- data/lib/rlsl/version.rb +1 -1
- data/lib/rlsl/wgsl/translator.rb +46 -39
- data/lib/rlsl/wgsl/uniform_layout.rb +25 -0
- data/lib/rlsl.rb +38 -15
- metadata +76 -11
|
@@ -3,17 +3,53 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
require "set"
|
|
5
5
|
|
|
6
|
+
require_relative "node_traversal"
|
|
7
|
+
require_relative "errors"
|
|
8
|
+
require_relative "parameter_list"
|
|
9
|
+
require_relative "ast_visitor/visitor_registry"
|
|
10
|
+
require_relative "ast_visitor/scope_context"
|
|
11
|
+
require_relative "ast_visitor/expression_visiting"
|
|
12
|
+
require_relative "ast_visitor/control_flow_visiting"
|
|
13
|
+
require_relative "ast_visitor/definition_visiting"
|
|
14
|
+
|
|
6
15
|
module RLSL
|
|
7
16
|
module Prism
|
|
8
17
|
class ASTVisitor
|
|
18
|
+
MAX_AST_DEPTH = 512
|
|
9
19
|
BINARY_OPERATORS = %w[+ - * / % == != < > <= >= && ||].freeze
|
|
10
20
|
UNARY_OPERATORS = %w[- !].freeze
|
|
21
|
+
TRANSPARENT_NODES = VisitorRegistry::TRANSPARENT_NODES
|
|
22
|
+
NODE_VISITORS = VisitorRegistry.build(
|
|
23
|
+
{}.tap do |visitors|
|
|
24
|
+
visitors[::Prism::ProgramNode] = :visit_program if defined?(::Prism::ProgramNode)
|
|
25
|
+
visitors[::Prism::StatementsNode] = :visit_statements if defined?(::Prism::StatementsNode)
|
|
26
|
+
end,
|
|
27
|
+
ExpressionVisiting::VISITORS,
|
|
28
|
+
ControlFlowVisiting::VISITORS,
|
|
29
|
+
DefinitionVisiting::VISITORS
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
include ExpressionVisiting
|
|
33
|
+
include ControlFlowVisiting
|
|
34
|
+
include DefinitionVisiting
|
|
11
35
|
|
|
12
36
|
def initialize(context = {})
|
|
13
37
|
@context = context
|
|
14
38
|
@uniforms = context[:uniforms] || {}
|
|
15
|
-
@
|
|
16
|
-
@
|
|
39
|
+
@source_name = context[:source_name] || "(shader source)"
|
|
40
|
+
@line_offset = context[:line_offset].to_i
|
|
41
|
+
params = context[:params] || []
|
|
42
|
+
@scope_context = ScopeContext.new(params: params)
|
|
43
|
+
positional_types = params.each_with_index.to_h do |name, index|
|
|
44
|
+
[name.to_sym, %i[vec2 vec2 uniforms][index]]
|
|
45
|
+
end
|
|
46
|
+
@parameter_types = { frag_coord: :vec2, resolution: :vec2, u: :uniforms }.merge(positional_types)
|
|
47
|
+
@parameter_bindings = { frag_coord: :frag_coord, resolution: :resolution, u: :u }
|
|
48
|
+
@implicit_loop_index = 0
|
|
49
|
+
@source_identifiers = Set.new
|
|
50
|
+
params.each_with_index do |name, index|
|
|
51
|
+
@parameter_bindings[name.to_sym] = %i[frag_coord resolution u][index]
|
|
52
|
+
end
|
|
17
53
|
end
|
|
18
54
|
|
|
19
55
|
def parse(source)
|
|
@@ -21,34 +57,39 @@ module RLSL
|
|
|
21
57
|
|
|
22
58
|
unless result.success?
|
|
23
59
|
errors = result.errors.map(&:message).join(", ")
|
|
24
|
-
raise "Parse error: #{errors}"
|
|
60
|
+
raise RLSL::ParseError, "Parse error: #{errors}"
|
|
25
61
|
end
|
|
26
62
|
|
|
27
63
|
program = result.value
|
|
64
|
+
if NodeTraversal.depth_exceeds?(program, MAX_AST_DEPTH)
|
|
65
|
+
raise UnsupportedSyntaxError, "Shader syntax nesting exceeds #{MAX_AST_DEPTH} nodes"
|
|
66
|
+
end
|
|
67
|
+
@source_identifiers = NodeTraversal.each(program).filter_map do |node|
|
|
68
|
+
node.name.to_sym if node.respond_to?(:name)
|
|
69
|
+
end.to_set
|
|
70
|
+
|
|
28
71
|
visit(program)
|
|
29
72
|
end
|
|
30
73
|
|
|
31
74
|
def visit(node)
|
|
32
75
|
return nil if node.nil?
|
|
33
76
|
|
|
34
|
-
method_name =
|
|
35
|
-
if
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
77
|
+
method_name = NODE_VISITORS[node.class]
|
|
78
|
+
result = if method_name
|
|
79
|
+
send(method_name, node)
|
|
80
|
+
else
|
|
81
|
+
raise UnsupportedSyntaxError, "Unsupported Prism node: #{node.class}" unless transparent_node?(node)
|
|
82
|
+
|
|
83
|
+
visit_default(node)
|
|
84
|
+
end
|
|
85
|
+
attach_source_location(result, node.location)
|
|
86
|
+
rescue RLSL::Error => error
|
|
87
|
+
error.with_source_location(source_location(node.location))
|
|
88
|
+
raise
|
|
40
89
|
end
|
|
41
90
|
|
|
42
91
|
private
|
|
43
92
|
|
|
44
|
-
def node_type(node)
|
|
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
|
|
50
|
-
end
|
|
51
|
-
|
|
52
93
|
def visit_default(node)
|
|
53
94
|
children = []
|
|
54
95
|
node.child_nodes.compact.each do |child|
|
|
@@ -58,6 +99,10 @@ module RLSL
|
|
|
58
99
|
children.length == 1 ? children.first : children
|
|
59
100
|
end
|
|
60
101
|
|
|
102
|
+
def transparent_node?(node)
|
|
103
|
+
TRANSPARENT_NODES.include?(node.class)
|
|
104
|
+
end
|
|
105
|
+
|
|
61
106
|
def visit_program(node)
|
|
62
107
|
visit(node.statements)
|
|
63
108
|
end
|
|
@@ -67,304 +112,73 @@ module RLSL
|
|
|
67
112
|
IR::Block.new(statements)
|
|
68
113
|
end
|
|
69
114
|
|
|
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)
|
|
115
|
+
def visit_with_scoped_vars(node, params: [])
|
|
116
|
+
@scope_context.with_scope(params: params) { visit(node) }
|
|
108
117
|
end
|
|
109
118
|
|
|
110
|
-
def
|
|
111
|
-
|
|
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)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def visit_parentheses(node)
|
|
123
|
-
inner = visit(node.body)
|
|
124
|
-
if inner.is_a?(IR::Block) && inner.statements.length == 1
|
|
125
|
-
inner = inner.statements.first
|
|
126
|
-
end
|
|
127
|
-
IR::Parenthesized.new(inner)
|
|
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
|
|
119
|
+
def infer_param_type(name)
|
|
120
|
+
@parameter_types[name.to_sym]
|
|
238
121
|
end
|
|
239
122
|
|
|
240
|
-
def
|
|
241
|
-
|
|
242
|
-
right = visit(node.right)
|
|
243
|
-
IR::BinaryOp.new("&&", left, right, :bool)
|
|
123
|
+
def emitted_parameter_name(name)
|
|
124
|
+
@parameter_bindings[name.to_sym] || name.to_sym
|
|
244
125
|
end
|
|
245
126
|
|
|
246
|
-
def
|
|
247
|
-
|
|
248
|
-
right = visit(node.right)
|
|
249
|
-
IR::BinaryOp.new("||", left, right, :bool)
|
|
127
|
+
def extract_required_params(node)
|
|
128
|
+
ParameterList.required_names(node).map(&:to_sym)
|
|
250
129
|
end
|
|
251
130
|
|
|
252
|
-
def
|
|
253
|
-
|
|
254
|
-
IR::UnaryOp.new("!", operand, :bool)
|
|
255
|
-
end
|
|
131
|
+
def extract_block_params(node)
|
|
132
|
+
return [] unless node&.parameters
|
|
256
133
|
|
|
257
|
-
|
|
258
|
-
condition = visit(node.predicate)
|
|
259
|
-
body = visit(node.statements)
|
|
260
|
-
IR::WhileLoop.new(condition, body)
|
|
134
|
+
extract_required_params(node.parameters.parameters)
|
|
261
135
|
end
|
|
262
136
|
|
|
263
|
-
def
|
|
264
|
-
|
|
137
|
+
def parameter_reference?(name)
|
|
138
|
+
@scope_context.parameter?(name)
|
|
265
139
|
end
|
|
266
140
|
|
|
267
|
-
def
|
|
268
|
-
|
|
269
|
-
if %w[PI TAU].include?(name)
|
|
270
|
-
IR::Constant.new(name.to_sym, :float)
|
|
271
|
-
else
|
|
272
|
-
IR::VarRef.new(name.to_sym)
|
|
273
|
-
end
|
|
141
|
+
def fragment_parameter_reference?(name)
|
|
142
|
+
@scope_context.root_parameter?(name)
|
|
274
143
|
end
|
|
275
144
|
|
|
276
|
-
def
|
|
277
|
-
name
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if node.parameters
|
|
281
|
-
node.parameters.requireds&.each do |param|
|
|
282
|
-
params << param.name.to_sym
|
|
283
|
-
end
|
|
145
|
+
def emitted_assignment_name(name)
|
|
146
|
+
if fragment_parameter_reference?(name) && infer_param_type(name) == :uniforms
|
|
147
|
+
raise UnsupportedSyntaxError, "The fragment uniform parameter cannot be reassigned"
|
|
284
148
|
end
|
|
285
149
|
|
|
286
|
-
|
|
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)
|
|
150
|
+
fragment_parameter_reference?(name) ? emitted_parameter_name(name) : name
|
|
297
151
|
end
|
|
298
152
|
|
|
299
|
-
def
|
|
300
|
-
|
|
301
|
-
IR::ArrayLiteral.new(elements)
|
|
153
|
+
def known_variable?(name)
|
|
154
|
+
@scope_context.known_variable?(name)
|
|
302
155
|
end
|
|
303
156
|
|
|
304
|
-
def
|
|
305
|
-
|
|
306
|
-
index = visit(node.arguments.arguments.first)
|
|
307
|
-
IR::ArrayIndex.new(array, index)
|
|
157
|
+
def declare_variable(name)
|
|
158
|
+
@scope_context.declare(name)
|
|
308
159
|
end
|
|
309
160
|
|
|
310
|
-
def
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
current = current.parent
|
|
161
|
+
def next_implicit_loop_variable
|
|
162
|
+
loop do
|
|
163
|
+
name = :"_rlsl_i#{@implicit_loop_index}"
|
|
164
|
+
@implicit_loop_index += 1
|
|
165
|
+
return name unless @source_identifiers.include?(name)
|
|
316
166
|
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
167
|
end
|
|
327
168
|
|
|
328
|
-
def
|
|
329
|
-
|
|
330
|
-
value = visit(node.value)
|
|
169
|
+
def attach_source_location(result, prism_location)
|
|
170
|
+
return result unless result.is_a?(IR::Node)
|
|
331
171
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
def visit_constant_write(node)
|
|
336
|
-
name = node.name.to_sym
|
|
337
|
-
value = visit(node.value)
|
|
338
|
-
|
|
339
|
-
IR::GlobalDecl.new(name, value, is_const: true, is_static: true)
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
def visit_multi_write(node)
|
|
343
|
-
targets = node.lefts.map do |target|
|
|
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)
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
def visit_local_variable_target(node)
|
|
354
|
-
name = node.name.to_sym
|
|
355
|
-
@declared_vars.add(name)
|
|
356
|
-
IR::VarRef.new(name)
|
|
172
|
+
result.location ||= source_location(prism_location)
|
|
173
|
+
result
|
|
357
174
|
end
|
|
358
175
|
|
|
359
|
-
def
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
else
|
|
366
|
-
nil
|
|
367
|
-
end
|
|
176
|
+
def source_location(prism_location)
|
|
177
|
+
RLSL::SourceLocation.new(
|
|
178
|
+
source_name: @source_name,
|
|
179
|
+
line: @line_offset + prism_location.start_line,
|
|
180
|
+
column: prism_location.start_column + 1
|
|
181
|
+
)
|
|
368
182
|
end
|
|
369
183
|
end
|
|
370
184
|
end
|
|
@@ -0,0 +1,131 @@
|
|
|
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 common floating interpolated].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, targets: %i[glsl wgsl msl] },
|
|
16
|
+
mat3: { args: %i[any any any any any any any any any], returns: :mat3, variadic: true, min_args: 1, targets: %i[glsl wgsl msl] },
|
|
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, targets: %i[glsl wgsl msl] },
|
|
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: :floating },
|
|
31
|
+
|
|
32
|
+
abs: { args: [:any], returns: :same },
|
|
33
|
+
sign: { args: [:any], returns: :same },
|
|
34
|
+
floor: { args: [:any], returns: :floating },
|
|
35
|
+
ceil: { args: [:any], returns: :floating },
|
|
36
|
+
fract: { args: [:any], returns: :floating },
|
|
37
|
+
mod: { args: %i[float float], returns: :float },
|
|
38
|
+
min: { args: %i[any any], returns: :common },
|
|
39
|
+
max: { args: %i[any any], returns: :common },
|
|
40
|
+
clamp: { args: %i[any any any], returns: :common },
|
|
41
|
+
mix: { args: %i[any any float], returns: :interpolated },
|
|
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, targets: [:c] },
|
|
54
|
+
hash22: { args: [:vec2], returns: :vec2, targets: [:c] },
|
|
55
|
+
|
|
56
|
+
lessThan: { args: %i[any any], returns: :bool, targets: [] },
|
|
57
|
+
lessThanEqual: { args: %i[any any], returns: :bool, targets: [] },
|
|
58
|
+
greaterThan: { args: %i[any any], returns: :bool, targets: [] },
|
|
59
|
+
greaterThanEqual: { args: %i[any any], returns: :bool, targets: [] },
|
|
60
|
+
equal: { args: %i[any any], returns: :bool, targets: [] },
|
|
61
|
+
notEqual: { args: %i[any any], returns: :bool, targets: [] },
|
|
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, targets: %i[glsl wgsl msl] },
|
|
68
|
+
texture: { args: %i[sampler2D vec2], returns: :vec4, targets: %i[glsl wgsl msl] },
|
|
69
|
+
textureLod: { args: %i[sampler2D vec2 float], returns: :vec4, targets: %i[glsl wgsl msl] }
|
|
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 :common
|
|
105
|
+
type = OperatorRules.common_type(arg_types)
|
|
106
|
+
type if numeric_type?(type)
|
|
107
|
+
when :floating
|
|
108
|
+
type = arg_types.first
|
|
109
|
+
return :float if type == :int
|
|
110
|
+
|
|
111
|
+
type if type == :float || OperatorRules.vector_type?(type)
|
|
112
|
+
when :interpolated
|
|
113
|
+
type = OperatorRules.common_type(arg_types.first(2))
|
|
114
|
+
return :float if type == :int
|
|
115
|
+
|
|
116
|
+
type if numeric_type?(type)
|
|
117
|
+
when Symbol then rule
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def explicit_type?(type)
|
|
122
|
+
type.is_a?(Symbol) && !META_TYPES.include?(type)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def numeric_type?(type)
|
|
126
|
+
OperatorRules.scalar_type?(type) || OperatorRules.vector_type?(type)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|