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
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
require "prism"
|
|
4
4
|
require "set"
|
|
5
5
|
|
|
6
|
+
require_relative "node_traversal"
|
|
7
|
+
require_relative "errors"
|
|
8
|
+
require_relative "parameter_list"
|
|
6
9
|
require_relative "ast_visitor/visitor_registry"
|
|
7
10
|
require_relative "ast_visitor/scope_context"
|
|
8
11
|
require_relative "ast_visitor/expression_visiting"
|
|
@@ -11,9 +14,8 @@ require_relative "ast_visitor/definition_visiting"
|
|
|
11
14
|
|
|
12
15
|
module RLSL
|
|
13
16
|
module Prism
|
|
14
|
-
class UnsupportedSyntaxError < StandardError; end
|
|
15
|
-
|
|
16
17
|
class ASTVisitor
|
|
18
|
+
MAX_AST_DEPTH = 512
|
|
17
19
|
BINARY_OPERATORS = %w[+ - * / % == != < > <= >= && ||].freeze
|
|
18
20
|
UNARY_OPERATORS = %w[- !].freeze
|
|
19
21
|
TRANSPARENT_NODES = VisitorRegistry::TRANSPARENT_NODES
|
|
@@ -34,7 +36,20 @@ module RLSL
|
|
|
34
36
|
def initialize(context = {})
|
|
35
37
|
@context = context
|
|
36
38
|
@uniforms = context[:uniforms] || {}
|
|
37
|
-
@
|
|
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
|
|
38
53
|
end
|
|
39
54
|
|
|
40
55
|
def parse(source)
|
|
@@ -42,10 +57,17 @@ module RLSL
|
|
|
42
57
|
|
|
43
58
|
unless result.success?
|
|
44
59
|
errors = result.errors.map(&:message).join(", ")
|
|
45
|
-
raise "Parse error: #{errors}"
|
|
60
|
+
raise RLSL::ParseError, "Parse error: #{errors}"
|
|
46
61
|
end
|
|
47
62
|
|
|
48
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
|
+
|
|
49
71
|
visit(program)
|
|
50
72
|
end
|
|
51
73
|
|
|
@@ -53,11 +75,17 @@ module RLSL
|
|
|
53
75
|
return nil if node.nil?
|
|
54
76
|
|
|
55
77
|
method_name = NODE_VISITORS[node.class]
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
|
61
89
|
end
|
|
62
90
|
|
|
63
91
|
private
|
|
@@ -89,20 +117,15 @@ module RLSL
|
|
|
89
117
|
end
|
|
90
118
|
|
|
91
119
|
def infer_param_type(name)
|
|
92
|
-
|
|
93
|
-
when :frag_coord, :resolution
|
|
94
|
-
:vec2
|
|
95
|
-
when :u
|
|
96
|
-
:uniforms
|
|
97
|
-
else
|
|
98
|
-
nil
|
|
99
|
-
end
|
|
120
|
+
@parameter_types[name.to_sym]
|
|
100
121
|
end
|
|
101
122
|
|
|
102
|
-
def
|
|
103
|
-
|
|
123
|
+
def emitted_parameter_name(name)
|
|
124
|
+
@parameter_bindings[name.to_sym] || name.to_sym
|
|
125
|
+
end
|
|
104
126
|
|
|
105
|
-
|
|
127
|
+
def extract_required_params(node)
|
|
128
|
+
ParameterList.required_names(node).map(&:to_sym)
|
|
106
129
|
end
|
|
107
130
|
|
|
108
131
|
def extract_block_params(node)
|
|
@@ -115,6 +138,18 @@ module RLSL
|
|
|
115
138
|
@scope_context.parameter?(name)
|
|
116
139
|
end
|
|
117
140
|
|
|
141
|
+
def fragment_parameter_reference?(name)
|
|
142
|
+
@scope_context.root_parameter?(name)
|
|
143
|
+
end
|
|
144
|
+
|
|
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"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
fragment_parameter_reference?(name) ? emitted_parameter_name(name) : name
|
|
151
|
+
end
|
|
152
|
+
|
|
118
153
|
def known_variable?(name)
|
|
119
154
|
@scope_context.known_variable?(name)
|
|
120
155
|
end
|
|
@@ -122,6 +157,29 @@ module RLSL
|
|
|
122
157
|
def declare_variable(name)
|
|
123
158
|
@scope_context.declare(name)
|
|
124
159
|
end
|
|
160
|
+
|
|
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)
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def attach_source_location(result, prism_location)
|
|
170
|
+
return result unless result.is_a?(IR::Node)
|
|
171
|
+
|
|
172
|
+
result.location ||= source_location(prism_location)
|
|
173
|
+
result
|
|
174
|
+
end
|
|
175
|
+
|
|
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
|
+
)
|
|
182
|
+
end
|
|
125
183
|
end
|
|
126
184
|
end
|
|
127
185
|
end
|
|
@@ -5,16 +5,16 @@ module RLSL
|
|
|
5
5
|
module Builtins
|
|
6
6
|
module FunctionRegistry
|
|
7
7
|
ALL_TARGETS = %i[c glsl wgsl msl].freeze
|
|
8
|
-
META_TYPES = %i[any same first second third].freeze
|
|
8
|
+
META_TYPES = %i[any same first second third common floating interpolated].freeze
|
|
9
9
|
|
|
10
10
|
FUNCTIONS = {
|
|
11
11
|
vec2: { args: %i[any any], returns: :vec2, variadic: true, min_args: 1 },
|
|
12
12
|
vec3: { args: %i[any any any], returns: :vec3, variadic: true, min_args: 1 },
|
|
13
13
|
vec4: { args: %i[any any any any], returns: :vec4, variadic: true, min_args: 1 },
|
|
14
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 },
|
|
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
18
|
|
|
19
19
|
sin: { args: [:float], returns: :float },
|
|
20
20
|
cos: { args: [:float], returns: :float },
|
|
@@ -27,18 +27,18 @@ module RLSL
|
|
|
27
27
|
pow: { args: %i[float float], returns: :float },
|
|
28
28
|
exp: { args: [:float], returns: :float },
|
|
29
29
|
log: { args: [:float], returns: :float },
|
|
30
|
-
sqrt: { args: [:any], returns: :
|
|
30
|
+
sqrt: { args: [:any], returns: :floating },
|
|
31
31
|
|
|
32
32
|
abs: { args: [:any], returns: :same },
|
|
33
33
|
sign: { args: [:any], returns: :same },
|
|
34
|
-
floor: { args: [:any], returns: :
|
|
35
|
-
ceil: { args: [:any], returns: :
|
|
36
|
-
fract: { args: [:any], returns: :
|
|
37
|
-
mod: { args: %i[
|
|
38
|
-
min: { args: %i[any any], returns: :
|
|
39
|
-
max: { args: %i[any any], returns: :
|
|
40
|
-
clamp: { args: %i[any any any], returns: :
|
|
41
|
-
mix: { args: %i[any any float], returns: :
|
|
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
42
|
step: { args: %i[float any], returns: :second },
|
|
43
43
|
smoothstep: { args: %i[float float any], returns: :third },
|
|
44
44
|
|
|
@@ -50,23 +50,23 @@ module RLSL
|
|
|
50
50
|
reflect: { args: %i[any any], returns: :first },
|
|
51
51
|
refract: { args: %i[any any float], returns: :first },
|
|
52
52
|
|
|
53
|
-
hash21: { args: [:vec2], returns: :float },
|
|
54
|
-
hash22: { args: [:vec2], returns: :vec2 },
|
|
53
|
+
hash21: { args: [:vec2], returns: :float, targets: [:c] },
|
|
54
|
+
hash22: { args: [:vec2], returns: :vec2, targets: [:c] },
|
|
55
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 },
|
|
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
62
|
|
|
63
63
|
inverse: { args: [:any], returns: :same, targets: %i[glsl wgsl msl] },
|
|
64
64
|
transpose: { args: [:any], returns: :same, targets: %i[glsl wgsl msl] },
|
|
65
65
|
determinant: { args: [:any], returns: :float, targets: %i[glsl wgsl msl] },
|
|
66
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 }
|
|
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
70
|
}.freeze
|
|
71
71
|
|
|
72
72
|
module_function
|
|
@@ -101,6 +101,19 @@ module RLSL
|
|
|
101
101
|
when :first then arg_types.first
|
|
102
102
|
when :second then arg_types[1]
|
|
103
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)
|
|
104
117
|
when Symbol then rule
|
|
105
118
|
end
|
|
106
119
|
end
|
|
@@ -108,6 +121,10 @@ module RLSL
|
|
|
108
121
|
def explicit_type?(type)
|
|
109
122
|
type.is_a?(Symbol) && !META_TYPES.include?(type)
|
|
110
123
|
end
|
|
124
|
+
|
|
125
|
+
def numeric_type?(type)
|
|
126
|
+
OperatorRules.scalar_type?(type) || OperatorRules.vector_type?(type)
|
|
127
|
+
end
|
|
111
128
|
end
|
|
112
129
|
end
|
|
113
130
|
end
|
|
@@ -39,6 +39,7 @@ module RLSL
|
|
|
39
39
|
|
|
40
40
|
def binary_op_result_type(op, left_type, right_type)
|
|
41
41
|
op_kind = BINARY_OPERATORS[op.to_s]
|
|
42
|
+
validate_operand_shapes!(op, left_type, right_type)
|
|
42
43
|
|
|
43
44
|
case op_kind
|
|
44
45
|
when :comparison, :logical
|
|
@@ -78,6 +79,14 @@ module RLSL
|
|
|
78
79
|
%i[float int].include?(type)
|
|
79
80
|
end
|
|
80
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
|
+
|
|
81
90
|
def scalar_arithmetic_result_type(op, left_type, right_type)
|
|
82
91
|
return :float unless scalar_type?(left_type) && scalar_type?(right_type)
|
|
83
92
|
return :float if op.to_s == "/"
|
|
@@ -93,6 +102,21 @@ module RLSL
|
|
|
93
102
|
when :mat4 then :vec4
|
|
94
103
|
end
|
|
95
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
|
|
96
120
|
end
|
|
97
121
|
end
|
|
98
122
|
end
|
|
@@ -12,7 +12,7 @@ module RLSL
|
|
|
12
12
|
}.freeze
|
|
13
13
|
|
|
14
14
|
SINGLE_COMPONENT_FIELDS = %w[x y z w r g b a s t p q].freeze
|
|
15
|
-
SWIZZLE_PATTERNS = /\A[
|
|
15
|
+
SWIZZLE_PATTERNS = /\A(?:[xyzw]{2,4}|[rgba]{2,4}|[stpq]{2,4})\z/
|
|
16
16
|
|
|
17
17
|
module_function
|
|
18
18
|
|
|
@@ -32,6 +32,15 @@ module RLSL
|
|
|
32
32
|
else :float
|
|
33
33
|
end
|
|
34
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
|
|
35
44
|
end
|
|
36
45
|
end
|
|
37
46
|
end
|
data/lib/rlsl/prism/builtins.rb
CHANGED
|
@@ -51,6 +51,10 @@ module RLSL
|
|
|
51
51
|
SwizzleRules.swizzle_type(components)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
|
+
def valid_swizzle_for_type?(components, receiver_type)
|
|
55
|
+
SwizzleRules.valid_for_type?(components, receiver_type)
|
|
56
|
+
end
|
|
57
|
+
|
|
54
58
|
def resolve_return_type(rule, arg_types)
|
|
55
59
|
FunctionRegistry.resolve_return_type(rule, arg_types)
|
|
56
60
|
end
|
|
@@ -71,6 +75,10 @@ module RLSL
|
|
|
71
75
|
OperatorRules.scalar_type?(type)
|
|
72
76
|
end
|
|
73
77
|
|
|
78
|
+
def common_type(types)
|
|
79
|
+
OperatorRules.common_type(types)
|
|
80
|
+
end
|
|
81
|
+
|
|
74
82
|
def matrix_vector_result(matrix_type)
|
|
75
83
|
OperatorRules.matrix_vector_result(matrix_type)
|
|
76
84
|
end
|
|
@@ -6,8 +6,7 @@ module RLSL
|
|
|
6
6
|
class BaseEmitter
|
|
7
7
|
module ControlFlowEmission
|
|
8
8
|
def emit_tuple_return(node)
|
|
9
|
-
|
|
10
|
-
"#{indent}return (#{current_return_struct_name}){#{elements}};\n"
|
|
9
|
+
"#{indent}return #{emit_tuple_value(node)};\n"
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def emit_if_statement(node)
|
|
@@ -17,15 +16,18 @@ module RLSL
|
|
|
17
16
|
def emit_conditional(node, needs_return:)
|
|
18
17
|
condition = emit(node.condition)
|
|
19
18
|
then_code = emit_branch(node.then_branch, needs_return: needs_return)
|
|
19
|
+
declarations = emit_hoisted_declarations(node)
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
unless node.else_branch
|
|
22
|
+
return "#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}}#{needs_return ? "\n" : ""}"
|
|
23
|
+
end
|
|
22
24
|
|
|
23
25
|
if elsif_node?(node.else_branch)
|
|
24
26
|
elsif_code = emit_elsif(node.else_branch, needs_return: needs_return)
|
|
25
|
-
"#{indent}if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}#{needs_return ? "\n" : ""}"
|
|
27
|
+
"#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}#{needs_return ? "\n" : ""}"
|
|
26
28
|
else
|
|
27
29
|
else_code = emit_branch(node.else_branch, needs_return: needs_return)
|
|
28
|
-
"#{indent}if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}#{needs_return ? "\n" : ""}"
|
|
30
|
+
"#{declarations}#{indent}if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}#{needs_return ? "\n" : ""}"
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
@@ -53,16 +55,26 @@ module RLSL
|
|
|
53
55
|
end
|
|
54
56
|
|
|
55
57
|
def emit_return(node)
|
|
56
|
-
node.expression
|
|
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"
|
|
57
63
|
end
|
|
58
64
|
|
|
59
65
|
def emit_for_loop(node)
|
|
60
|
-
|
|
66
|
+
variable = node.variable
|
|
67
|
+
counter = loop_variable_mutated?(node) ? next_temporary_name("i") : variable
|
|
61
68
|
start_val = emit(node.range_start)
|
|
62
69
|
end_val = emit(node.range_end)
|
|
63
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)
|
|
64
75
|
|
|
65
|
-
|
|
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}}"
|
|
66
78
|
end
|
|
67
79
|
|
|
68
80
|
def emit_while_loop(node)
|
|
@@ -76,6 +88,37 @@ module RLSL
|
|
|
76
88
|
"break"
|
|
77
89
|
end
|
|
78
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
|
+
|
|
79
122
|
end
|
|
80
123
|
end
|
|
81
124
|
end
|
|
@@ -12,14 +12,14 @@ module RLSL
|
|
|
12
12
|
end.join(", ")
|
|
13
13
|
|
|
14
14
|
if node.return_type.is_a?(Array)
|
|
15
|
-
@current_return_struct_name = "#{name}_result"
|
|
16
15
|
struct_def = emit_result_struct(name, node.return_type)
|
|
17
|
-
body =
|
|
18
|
-
|
|
19
|
-
|
|
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
20
|
else
|
|
21
|
-
body = emit_indented_block(node.body, needs_return: true)
|
|
22
|
-
"
|
|
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
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
@@ -29,11 +29,18 @@ module RLSL
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def current_return_struct_name
|
|
32
|
-
@
|
|
32
|
+
@return_struct_name_stack.last || "result"
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def emit_array_literal(node, for_static_init: false)
|
|
36
|
-
|
|
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(", ")
|
|
37
44
|
"{#{elements}}"
|
|
38
45
|
end
|
|
39
46
|
|
|
@@ -66,7 +73,7 @@ module RLSL
|
|
|
66
73
|
elements = emit_array_literal(node.initializer, for_static_init: true)
|
|
67
74
|
"#{prefix}#{elem_type} #{node.name}[#{size}] = #{elements}"
|
|
68
75
|
else
|
|
69
|
-
value = node.
|
|
76
|
+
value = node.is_static ? emit_for_static_init(node.initializer, true) : emit(node.initializer)
|
|
70
77
|
"#{prefix}#{type_name(node.type || :float)} #{node.name} = #{value}"
|
|
71
78
|
end
|
|
72
79
|
end
|
|
@@ -76,6 +83,8 @@ module RLSL
|
|
|
76
83
|
|
|
77
84
|
if node.value.is_a?(IR::FuncCall)
|
|
78
85
|
emit_multi_return_assignment(node, value_code)
|
|
86
|
+
elsif node.value.is_a?(IR::ArrayLiteral)
|
|
87
|
+
emit_literal_assignment(node)
|
|
79
88
|
else
|
|
80
89
|
emit_indexed_assignment(node, value_code)
|
|
81
90
|
end
|
|
@@ -85,18 +94,39 @@ module RLSL
|
|
|
85
94
|
|
|
86
95
|
def emit_multi_return_assignment(node, value_code)
|
|
87
96
|
func_name = node.value.name
|
|
88
|
-
|
|
97
|
+
temporary = next_temporary_name("result")
|
|
98
|
+
lines = [emit_temporary_declaration("#{func_name}_result", temporary, value_code)]
|
|
89
99
|
node.targets.each_with_index do |target, index|
|
|
90
|
-
lines << "#{
|
|
100
|
+
lines << "#{emit_multiple_assignment_target(target, node.declarations[index])} = #{temporary}.v#{index}"
|
|
91
101
|
end
|
|
92
102
|
lines.join(";\n#{indent}")
|
|
93
103
|
end
|
|
94
104
|
|
|
95
105
|
def emit_indexed_assignment(node, value_code)
|
|
96
106
|
node.targets.each_with_index.map do |target, index|
|
|
97
|
-
"#{
|
|
107
|
+
"#{emit_multiple_assignment_target(target, node.declarations[index])} = #{value_code}[#{index}]"
|
|
98
108
|
end.join(";\n#{indent}")
|
|
99
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
|
|
100
130
|
end
|
|
101
131
|
end
|
|
102
132
|
end
|
|
@@ -7,6 +7,14 @@ module RLSL
|
|
|
7
7
|
module ExpressionEmission
|
|
8
8
|
def emit_var_decl(node)
|
|
9
9
|
type = type_name(node.type || :float)
|
|
10
|
+
return "#{type} #{node.name}" unless node.initializer
|
|
11
|
+
|
|
12
|
+
if node.initializer.is_a?(IR::ArrayLiteral)
|
|
13
|
+
value = emit(node.initializer)
|
|
14
|
+
element_type = type_name(TypeShapes.element_type(node.type) || :float)
|
|
15
|
+
return "#{element_type} #{node.name}[#{node.initializer.elements.length}] = #{value}"
|
|
16
|
+
end
|
|
17
|
+
|
|
10
18
|
value = emit(node.initializer)
|
|
11
19
|
"#{type} #{node.name} = #{value}"
|
|
12
20
|
end
|
|
@@ -16,7 +24,7 @@ module RLSL
|
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
def emit_literal(node)
|
|
19
|
-
format_number(node.value)
|
|
27
|
+
format_number(node.value, type: node.type)
|
|
20
28
|
end
|
|
21
29
|
|
|
22
30
|
def emit_bool_literal(node)
|
|
@@ -24,13 +32,17 @@ module RLSL
|
|
|
24
32
|
end
|
|
25
33
|
|
|
26
34
|
def emit_binary_op(node)
|
|
27
|
-
left = emit_with_precedence(node.left, node.operator)
|
|
28
|
-
right = emit_with_precedence(node.right, node.operator)
|
|
35
|
+
left = emit_with_precedence(node.left, node.operator, side: :left)
|
|
36
|
+
right = emit_with_precedence(node.right, node.operator, side: :right)
|
|
29
37
|
"#{left} #{node.operator} #{right}"
|
|
30
38
|
end
|
|
31
39
|
|
|
32
40
|
def emit_unary_op(node)
|
|
33
|
-
|
|
41
|
+
operand = emit(node.operand)
|
|
42
|
+
operand = "(#{operand})" if node.operand.is_a?(IR::BinaryOp) ||
|
|
43
|
+
node.operand.is_a?(IR::Ternary) ||
|
|
44
|
+
node.operand.is_a?(IR::UnaryOp)
|
|
45
|
+
"#{node.operator}#{operand}"
|
|
34
46
|
end
|
|
35
47
|
|
|
36
48
|
def emit_func_call(node)
|
|
@@ -85,6 +97,10 @@ module RLSL
|
|
|
85
97
|
end
|
|
86
98
|
"#{array}[#{index}]"
|
|
87
99
|
end
|
|
100
|
+
|
|
101
|
+
def emit_typed_argument(node, _expected_type)
|
|
102
|
+
emit(node)
|
|
103
|
+
end
|
|
88
104
|
end
|
|
89
105
|
end
|
|
90
106
|
end
|
|
@@ -27,10 +27,16 @@ module RLSL
|
|
|
27
27
|
|
|
28
28
|
def emit_terminal_statement(node)
|
|
29
29
|
return emit(node, needs_return: true) if node.is_a?(IR::IfStatement)
|
|
30
|
+
if node.is_a?(IR::VarDecl)
|
|
31
|
+
return "#{emit_statement(node)}#{indent}return #{node.name};\n"
|
|
32
|
+
end
|
|
33
|
+
if node.is_a?(IR::Assignment)
|
|
34
|
+
return "#{emit_statement(node)}#{indent}return #{emit(node.target)};\n"
|
|
35
|
+
end
|
|
30
36
|
return emit_statement(node) if terminal_passthrough_node?(node)
|
|
31
37
|
return emit_tuple_return(node) if node.is_a?(IR::ArrayLiteral)
|
|
32
38
|
|
|
33
|
-
"#{indent}return #{
|
|
39
|
+
"#{indent}return #{emit_return_expression(node)};\n"
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
def emit_branch(node, needs_return:)
|