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