rlsl 0.1.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 +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE +21 -0
- data/README.md +170 -0
- data/Rakefile +12 -0
- data/lib/rlsl/base_translator.rb +109 -0
- data/lib/rlsl/code_generator.rb +231 -0
- data/lib/rlsl/compiled_shader.rb +24 -0
- data/lib/rlsl/function_context.rb +35 -0
- data/lib/rlsl/glsl/translator.rb +97 -0
- data/lib/rlsl/msl/shader.rb +83 -0
- data/lib/rlsl/msl/translator.rb +89 -0
- data/lib/rlsl/prism/ast_visitor.rb +371 -0
- data/lib/rlsl/prism/builtins.rb +197 -0
- data/lib/rlsl/prism/emitters/base_emitter.rb +480 -0
- data/lib/rlsl/prism/emitters/c_emitter.rb +153 -0
- data/lib/rlsl/prism/emitters/glsl_emitter.rb +74 -0
- data/lib/rlsl/prism/emitters/msl_emitter.rb +76 -0
- data/lib/rlsl/prism/emitters/wgsl_emitter.rb +89 -0
- data/lib/rlsl/prism/ir/nodes.rb +373 -0
- data/lib/rlsl/prism/source_extractor.rb +152 -0
- data/lib/rlsl/prism/transpiler.rb +128 -0
- data/lib/rlsl/prism/type_inference.rb +289 -0
- data/lib/rlsl/shader_builder.rb +165 -0
- data/lib/rlsl/types.rb +36 -0
- data/lib/rlsl/uniform_context.rb +28 -0
- data/lib/rlsl/version.rb +5 -0
- data/lib/rlsl/wgsl/translator.rb +93 -0
- data/lib/rlsl.rb +57 -0
- metadata +100 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module Prism
|
|
5
|
+
module Builtins
|
|
6
|
+
FUNCTIONS = {
|
|
7
|
+
vec2: { args: %i[any any], returns: :vec2, variadic: true, min_args: 1 },
|
|
8
|
+
vec3: { args: %i[any any any], returns: :vec3, variadic: true, min_args: 1 },
|
|
9
|
+
vec4: { args: %i[any any any any], returns: :vec4, variadic: true, min_args: 1 },
|
|
10
|
+
|
|
11
|
+
mat2: { args: %i[any any any any], returns: :mat2, variadic: true, min_args: 1 },
|
|
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/
|
|
101
|
+
|
|
102
|
+
class << self
|
|
103
|
+
def function?(name)
|
|
104
|
+
FUNCTIONS.key?(name.to_sym)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def function_signature(name)
|
|
108
|
+
FUNCTIONS[name.to_sym]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def binary_operator?(op)
|
|
112
|
+
BINARY_OPERATORS.key?(op.to_s)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def unary_operator?(op)
|
|
116
|
+
UNARY_OPERATORS.key?(op.to_s)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def single_component_field?(name)
|
|
120
|
+
SINGLE_COMPONENT_FIELDS.include?(name.to_s)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def swizzle?(name)
|
|
124
|
+
name.to_s.match?(SWIZZLE_PATTERNS)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def swizzle_type(components)
|
|
128
|
+
case components.length
|
|
129
|
+
when 2 then :vec2
|
|
130
|
+
when 3 then :vec3
|
|
131
|
+
when 4 then :vec4
|
|
132
|
+
else :float
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def resolve_return_type(rule, arg_types)
|
|
137
|
+
case rule
|
|
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
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def binary_op_result_type(op, left_type, right_type)
|
|
147
|
+
op_kind = BINARY_OPERATORS[op.to_s]
|
|
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
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def vector_type?(type)
|
|
176
|
+
%i[vec2 vec3 vec4].include?(type)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def matrix_type?(type)
|
|
180
|
+
%i[mat2 mat3 mat4].include?(type)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def scalar_type?(type)
|
|
184
|
+
%i[float int].include?(type)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def matrix_vector_result(matrix_type)
|
|
188
|
+
case matrix_type
|
|
189
|
+
when :mat2 then :vec2
|
|
190
|
+
when :mat3 then :vec3
|
|
191
|
+
when :mat4 then :vec4
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RLSL
|
|
4
|
+
module Prism
|
|
5
|
+
module Emitters
|
|
6
|
+
class BaseEmitter
|
|
7
|
+
PRECEDENCE = {
|
|
8
|
+
"||" => 1,
|
|
9
|
+
"&&" => 2,
|
|
10
|
+
"==" => 3, "!=" => 3,
|
|
11
|
+
"<" => 4, ">" => 4, "<=" => 4, ">=" => 4,
|
|
12
|
+
"+" => 5, "-" => 5,
|
|
13
|
+
"*" => 6, "/" => 6, "%" => 6
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
attr_reader :indent_level
|
|
17
|
+
|
|
18
|
+
def initialize
|
|
19
|
+
@indent_level = 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def emit(node, needs_return: false)
|
|
23
|
+
case node
|
|
24
|
+
when IR::Block
|
|
25
|
+
emit_block(node, needs_return: needs_return)
|
|
26
|
+
when IR::VarDecl
|
|
27
|
+
emit_var_decl(node)
|
|
28
|
+
when IR::VarRef
|
|
29
|
+
emit_var_ref(node)
|
|
30
|
+
when IR::Literal
|
|
31
|
+
emit_literal(node)
|
|
32
|
+
when IR::BoolLiteral
|
|
33
|
+
emit_bool_literal(node)
|
|
34
|
+
when IR::BinaryOp
|
|
35
|
+
emit_binary_op(node)
|
|
36
|
+
when IR::UnaryOp
|
|
37
|
+
emit_unary_op(node)
|
|
38
|
+
when IR::FuncCall
|
|
39
|
+
emit_func_call(node)
|
|
40
|
+
when IR::FieldAccess
|
|
41
|
+
emit_field_access(node)
|
|
42
|
+
when IR::Swizzle
|
|
43
|
+
emit_swizzle(node)
|
|
44
|
+
when IR::IfStatement
|
|
45
|
+
emit_if_statement(node)
|
|
46
|
+
when IR::Return
|
|
47
|
+
emit_return(node)
|
|
48
|
+
when IR::Assignment
|
|
49
|
+
emit_assignment(node)
|
|
50
|
+
when IR::ForLoop
|
|
51
|
+
emit_for_loop(node)
|
|
52
|
+
when IR::WhileLoop
|
|
53
|
+
emit_while_loop(node)
|
|
54
|
+
when IR::Break
|
|
55
|
+
emit_break(node)
|
|
56
|
+
when IR::Constant
|
|
57
|
+
emit_constant(node)
|
|
58
|
+
when IR::Parenthesized
|
|
59
|
+
emit_parenthesized(node)
|
|
60
|
+
when IR::FunctionDefinition
|
|
61
|
+
emit_function_definition(node)
|
|
62
|
+
when IR::ArrayLiteral
|
|
63
|
+
emit_array_literal(node)
|
|
64
|
+
when IR::ArrayIndex
|
|
65
|
+
emit_array_index(node)
|
|
66
|
+
when IR::GlobalDecl
|
|
67
|
+
emit_global_decl(node)
|
|
68
|
+
when IR::MultipleAssignment
|
|
69
|
+
emit_multiple_assignment(node)
|
|
70
|
+
else
|
|
71
|
+
raise "Unknown IR node: #{node.class}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
protected
|
|
76
|
+
|
|
77
|
+
def type_name(type)
|
|
78
|
+
type.to_s
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def emit_block(node, needs_return: false)
|
|
82
|
+
statements = node.statements
|
|
83
|
+
return "" if statements.empty?
|
|
84
|
+
|
|
85
|
+
if needs_return && statements.any?
|
|
86
|
+
result = statements[0...-1].map { |stmt| emit_statement(stmt) }.join
|
|
87
|
+
result + emit_with_return(statements.last)
|
|
88
|
+
else
|
|
89
|
+
statements.map { |stmt| emit_statement(stmt) }.join
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def emit_with_return(node)
|
|
94
|
+
if node.is_a?(IR::IfStatement)
|
|
95
|
+
emit_if_with_return(node)
|
|
96
|
+
elsif node.is_a?(IR::Return)
|
|
97
|
+
emit_statement(node)
|
|
98
|
+
elsif node.is_a?(IR::FunctionDefinition) || node.is_a?(IR::GlobalDecl) ||
|
|
99
|
+
node.is_a?(IR::MultipleAssignment)
|
|
100
|
+
emit_statement(node)
|
|
101
|
+
elsif node.is_a?(IR::ArrayLiteral)
|
|
102
|
+
emit_tuple_return(node)
|
|
103
|
+
else
|
|
104
|
+
"#{indent}return #{emit(node)};\n"
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def emit_tuple_return(node)
|
|
109
|
+
elements = node.elements.map { |elem| emit(elem) }.join(", ")
|
|
110
|
+
"#{indent}return (#{current_return_struct_name}){#{elements}};\n"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def emit_if_with_return(node)
|
|
114
|
+
condition = emit(node.condition)
|
|
115
|
+
then_code = emit_branch_with_return(node.then_branch)
|
|
116
|
+
|
|
117
|
+
if node.else_branch
|
|
118
|
+
if elsif_node?(node.else_branch)
|
|
119
|
+
elsif_code = emit_elsif_with_return(node.else_branch)
|
|
120
|
+
"#{indent}if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}\n"
|
|
121
|
+
else
|
|
122
|
+
else_code = emit_branch_with_return(node.else_branch)
|
|
123
|
+
"#{indent}if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}\n"
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
"#{indent}if (#{condition}) {\n#{then_code}#{indent}}\n"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def emit_elsif_with_return(node)
|
|
131
|
+
if_node = node.is_a?(IR::Block) ? node.statements.first : node
|
|
132
|
+
condition = emit(if_node.condition)
|
|
133
|
+
then_code = emit_branch_with_return(if_node.then_branch)
|
|
134
|
+
|
|
135
|
+
if if_node.else_branch
|
|
136
|
+
if elsif_node?(if_node.else_branch)
|
|
137
|
+
elsif_code = emit_elsif_with_return(if_node.else_branch)
|
|
138
|
+
"else if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}"
|
|
139
|
+
else
|
|
140
|
+
else_code = emit_branch_with_return(if_node.else_branch)
|
|
141
|
+
"else if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}"
|
|
142
|
+
end
|
|
143
|
+
else
|
|
144
|
+
"else if (#{condition}) {\n#{then_code}#{indent}}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def emit_branch_with_return(node)
|
|
149
|
+
@indent_level += 1
|
|
150
|
+
result = if node.is_a?(IR::Block)
|
|
151
|
+
emit_block(node, needs_return: true)
|
|
152
|
+
else
|
|
153
|
+
emit_with_return(node)
|
|
154
|
+
end
|
|
155
|
+
@indent_level -= 1
|
|
156
|
+
result
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def emit_statement(node, needs_return: false)
|
|
160
|
+
if needs_return && !node.is_a?(IR::Return) && !node.is_a?(IR::IfStatement) &&
|
|
161
|
+
!node.is_a?(IR::ForLoop) && !node.is_a?(IR::WhileLoop) && !node.is_a?(IR::VarDecl) &&
|
|
162
|
+
!node.is_a?(IR::Assignment) && !node.is_a?(IR::FunctionDefinition) &&
|
|
163
|
+
!node.is_a?(IR::GlobalDecl) && !node.is_a?(IR::MultipleAssignment)
|
|
164
|
+
return "#{indent}return #{emit(node)};\n"
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
code = emit(node)
|
|
168
|
+
if node.is_a?(IR::IfStatement) || node.is_a?(IR::ForLoop) ||
|
|
169
|
+
node.is_a?(IR::WhileLoop) || node.is_a?(IR::FunctionDefinition)
|
|
170
|
+
"#{indent}#{code}\n"
|
|
171
|
+
else
|
|
172
|
+
"#{indent}#{code};\n"
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def emit_var_decl(node)
|
|
177
|
+
type = type_name(node.type || :float)
|
|
178
|
+
value = emit(node.initializer)
|
|
179
|
+
"#{type} #{node.name} = #{value}"
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def emit_var_ref(node)
|
|
183
|
+
node.name.to_s
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def emit_literal(node)
|
|
187
|
+
format_number(node.value)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def emit_bool_literal(node)
|
|
191
|
+
node.value.to_s
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def emit_binary_op(node)
|
|
195
|
+
left = emit_with_precedence(node.left, node.operator)
|
|
196
|
+
right = emit_with_precedence(node.right, node.operator)
|
|
197
|
+
"#{left} #{node.operator} #{right}"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def emit_unary_op(node)
|
|
201
|
+
operand = emit(node.operand)
|
|
202
|
+
"#{node.operator}#{operand}"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def emit_func_call(node)
|
|
206
|
+
func_name = function_name(node.name)
|
|
207
|
+
args = node.args.map { |arg| emit(arg) }.join(", ")
|
|
208
|
+
|
|
209
|
+
if node.receiver
|
|
210
|
+
receiver = emit(node.receiver)
|
|
211
|
+
"#{func_name}(#{receiver}, #{args})"
|
|
212
|
+
else
|
|
213
|
+
"#{func_name}(#{args})"
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def emit_field_access(node)
|
|
218
|
+
receiver = emit(node.receiver)
|
|
219
|
+
"#{receiver}.#{node.field}"
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def emit_swizzle(node)
|
|
223
|
+
receiver = emit(node.receiver)
|
|
224
|
+
"#{receiver}.#{node.components}"
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def emit_if_statement(node)
|
|
228
|
+
condition = emit(node.condition)
|
|
229
|
+
then_code = emit_indented_block(node.then_branch)
|
|
230
|
+
|
|
231
|
+
if node.else_branch
|
|
232
|
+
if elsif_node?(node.else_branch)
|
|
233
|
+
elsif_code = emit_elsif(node.else_branch)
|
|
234
|
+
"if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}"
|
|
235
|
+
else
|
|
236
|
+
else_code = emit_indented_block(node.else_branch)
|
|
237
|
+
"if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}"
|
|
238
|
+
end
|
|
239
|
+
else
|
|
240
|
+
"if (#{condition}) {\n#{then_code}#{indent}}"
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def elsif_node?(node)
|
|
245
|
+
return true if node.is_a?(IR::IfStatement)
|
|
246
|
+
return false unless node.is_a?(IR::Block)
|
|
247
|
+
|
|
248
|
+
node.statements.length == 1 && node.statements.first.is_a?(IR::IfStatement)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def emit_elsif(node)
|
|
252
|
+
if_node = node.is_a?(IR::Block) ? node.statements.first : node
|
|
253
|
+
condition = emit(if_node.condition)
|
|
254
|
+
then_code = emit_indented_block(if_node.then_branch)
|
|
255
|
+
|
|
256
|
+
if if_node.else_branch
|
|
257
|
+
if elsif_node?(if_node.else_branch)
|
|
258
|
+
elsif_code = emit_elsif(if_node.else_branch)
|
|
259
|
+
"else if (#{condition}) {\n#{then_code}#{indent}} #{elsif_code}"
|
|
260
|
+
else
|
|
261
|
+
else_code = emit_indented_block(if_node.else_branch)
|
|
262
|
+
"else if (#{condition}) {\n#{then_code}#{indent}} else {\n#{else_code}#{indent}}"
|
|
263
|
+
end
|
|
264
|
+
else
|
|
265
|
+
"else if (#{condition}) {\n#{then_code}#{indent}}"
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def emit_return(node)
|
|
270
|
+
if node.expression
|
|
271
|
+
"return #{emit(node.expression)}"
|
|
272
|
+
else
|
|
273
|
+
"return"
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def emit_assignment(node)
|
|
278
|
+
target = emit(node.target)
|
|
279
|
+
value = emit(node.value)
|
|
280
|
+
"#{target} = #{value}"
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def emit_for_loop(node)
|
|
284
|
+
var = node.variable
|
|
285
|
+
start_val = emit(node.range_start)
|
|
286
|
+
end_val = emit(node.range_end)
|
|
287
|
+
body = emit_indented_block(node.body)
|
|
288
|
+
|
|
289
|
+
"for (int #{var} = #{start_val}; #{var} < #{end_val}; #{var}++) {\n#{body}#{indent}}"
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def emit_while_loop(node)
|
|
293
|
+
condition = emit(node.condition)
|
|
294
|
+
body = emit_indented_block(node.body)
|
|
295
|
+
|
|
296
|
+
"while (#{condition}) {\n#{body}#{indent}}"
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def emit_break(_node)
|
|
300
|
+
"break"
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def emit_constant(node)
|
|
304
|
+
case node.name
|
|
305
|
+
when :PI
|
|
306
|
+
"3.14159265358979323846"
|
|
307
|
+
when :TAU
|
|
308
|
+
"6.28318530717958647692"
|
|
309
|
+
else
|
|
310
|
+
node.name.to_s
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def emit_parenthesized(node)
|
|
315
|
+
"(#{emit(node.expression)})"
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def emit_function_definition(node)
|
|
319
|
+
name = node.name
|
|
320
|
+
params = node.params.map do |param|
|
|
321
|
+
param_type = type_name(node.param_types[param] || :float)
|
|
322
|
+
"#{param_type} #{param}"
|
|
323
|
+
end.join(", ")
|
|
324
|
+
|
|
325
|
+
if node.return_type.is_a?(Array)
|
|
326
|
+
@current_return_struct_name = "#{name}_result"
|
|
327
|
+
struct_def = emit_result_struct(name, node.return_type)
|
|
328
|
+
|
|
329
|
+
body = emit_indented_block(node.body, needs_return: true)
|
|
330
|
+
|
|
331
|
+
@current_return_struct_name = nil
|
|
332
|
+
"#{struct_def}static inline #{name}_result #{name}(#{params}) {\n#{body}\n#{indent}}\n"
|
|
333
|
+
else
|
|
334
|
+
return_type = type_name(node.return_type || :float)
|
|
335
|
+
|
|
336
|
+
body = emit_indented_block(node.body, needs_return: true)
|
|
337
|
+
|
|
338
|
+
"static inline #{return_type} #{name}(#{params}) {\n#{body}\n#{indent}}\n"
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def emit_result_struct(func_name, types)
|
|
343
|
+
fields = types.each_with_index.map do |t, i|
|
|
344
|
+
"#{type_name(t)} v#{i};"
|
|
345
|
+
end.join(" ")
|
|
346
|
+
"typedef struct { #{fields} } #{func_name}_result;\n"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def current_return_struct_name
|
|
350
|
+
@current_return_struct_name || "result"
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def emit_array_literal(node, for_static_init: false)
|
|
354
|
+
elements = node.elements.map { |elem| emit_for_static_init(elem, for_static_init) }.join(", ")
|
|
355
|
+
"{#{elements}}"
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def emit_for_static_init(node, for_static_init)
|
|
359
|
+
return emit(node) unless for_static_init
|
|
360
|
+
|
|
361
|
+
case node
|
|
362
|
+
when IR::FuncCall
|
|
363
|
+
if %i[vec2 vec3 vec4].include?(node.name)
|
|
364
|
+
args = node.args.map { |arg| emit_for_static_init(arg, true) }.join(", ")
|
|
365
|
+
"{#{args}}"
|
|
366
|
+
else
|
|
367
|
+
emit(node)
|
|
368
|
+
end
|
|
369
|
+
when IR::ArrayLiteral
|
|
370
|
+
emit_array_literal(node, for_static_init: true)
|
|
371
|
+
else
|
|
372
|
+
emit(node)
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def emit_array_index(node)
|
|
377
|
+
array = emit(node.array)
|
|
378
|
+
index = if node.index.is_a?(IR::Literal) && node.index.value.to_i == node.index.value
|
|
379
|
+
node.index.value.to_i.to_s
|
|
380
|
+
else
|
|
381
|
+
emit(node.index)
|
|
382
|
+
end
|
|
383
|
+
"#{array}[#{index}]"
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def emit_global_decl(node)
|
|
387
|
+
name = node.name
|
|
388
|
+
|
|
389
|
+
if node.initializer.is_a?(IR::ArrayLiteral)
|
|
390
|
+
elem_type = type_name(node.element_type || :float)
|
|
391
|
+
size = node.array_size || node.initializer.elements.length
|
|
392
|
+
elements = emit_array_literal(node.initializer, for_static_init: true)
|
|
393
|
+
|
|
394
|
+
prefix = ""
|
|
395
|
+
prefix += "static " if node.is_static
|
|
396
|
+
prefix += "const " if node.is_const
|
|
397
|
+
|
|
398
|
+
"#{prefix}#{elem_type} #{name}[#{size}] = #{elements}"
|
|
399
|
+
else
|
|
400
|
+
var_type = type_name(node.type || :float)
|
|
401
|
+
value = if node.is_const
|
|
402
|
+
emit_for_static_init(node.initializer, true)
|
|
403
|
+
else
|
|
404
|
+
emit(node.initializer)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
prefix = ""
|
|
408
|
+
prefix += "static " if node.is_static
|
|
409
|
+
prefix += "const " if node.is_const
|
|
410
|
+
|
|
411
|
+
"#{prefix}#{var_type} #{name} = #{value}"
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def emit_multiple_assignment(node)
|
|
416
|
+
value_code = emit(node.value)
|
|
417
|
+
|
|
418
|
+
if node.value.is_a?(IR::FuncCall)
|
|
419
|
+
func_name = node.value.name
|
|
420
|
+
struct_name = "#{func_name}_result"
|
|
421
|
+
|
|
422
|
+
lines = []
|
|
423
|
+
lines << "#{struct_name} _tmp_#{func_name} = #{value_code}"
|
|
424
|
+
node.targets.each_with_index do |target, i|
|
|
425
|
+
target_type = type_name(target.type || :float)
|
|
426
|
+
lines << "#{target_type} #{target.name} = _tmp_#{func_name}.v#{i}"
|
|
427
|
+
end
|
|
428
|
+
lines.join(";\n#{indent}")
|
|
429
|
+
else
|
|
430
|
+
lines = []
|
|
431
|
+
node.targets.each_with_index do |target, i|
|
|
432
|
+
target_type = type_name(target.type || :float)
|
|
433
|
+
lines << "#{target_type} #{target.name} = #{value_code}[#{i}]"
|
|
434
|
+
end
|
|
435
|
+
lines.join(";\n#{indent}")
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def format_number(value)
|
|
440
|
+
if value.is_a?(Float)
|
|
441
|
+
formatted = value.to_s
|
|
442
|
+
formatted += ".0" unless formatted.include?(".")
|
|
443
|
+
formatted
|
|
444
|
+
else
|
|
445
|
+
"#{value}.0"
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def indent
|
|
450
|
+
" " * @indent_level
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def emit_indented_block(node, needs_return: false)
|
|
454
|
+
@indent_level += 1
|
|
455
|
+
result = if node.is_a?(IR::Block)
|
|
456
|
+
emit_block(node, needs_return: needs_return)
|
|
457
|
+
else
|
|
458
|
+
emit_statement(node, needs_return: needs_return)
|
|
459
|
+
end
|
|
460
|
+
@indent_level -= 1
|
|
461
|
+
result
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def emit_with_precedence(node, parent_op)
|
|
465
|
+
code = emit(node)
|
|
466
|
+
if node.is_a?(IR::BinaryOp)
|
|
467
|
+
node_prec = PRECEDENCE[node.operator] || 10
|
|
468
|
+
parent_prec = PRECEDENCE[parent_op] || 10
|
|
469
|
+
return "(#{code})" if node_prec < parent_prec
|
|
470
|
+
end
|
|
471
|
+
code
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def function_name(name)
|
|
475
|
+
name.to_s
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
end
|
|
480
|
+
end
|