Class: Idl::ForLoopAst
- Inherits:
-
AstNode
show all
- Includes:
- Executable, Returns
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/find_src_registers.rb,
lib/idlc/passes/reachable_functions.rb,
lib/idlc/passes/reachable_exceptions.rb
Constant Summary
collapse
- StmtType =
T.type_alias { T.any(StatementAst, ReturnStatementAst, IfAst, ForLoopAst, ImplicationStatementAst) }
Constants inherited
from AstNode
AstNode::Bits1Type, AstNode::Bits32Type, AstNode::Bits64Type, AstNode::BoolType, AstNode::ConstBoolType, AstNode::PossiblyUnknownBits1Type, AstNode::PossiblyUnknownBits32Type, AstNode::PossiblyUnknownBits64Type, AstNode::ReachableFunctionCacheType, AstNode::StringType, AstNode::VoidType
Instance Attribute Summary
Attributes inherited from AstNode
#children, #input, #interval, #parent
Class Method Summary
collapse
Instance Method Summary
collapse
-
#condition ⇒ Object
-
#const_eval?(symtab) ⇒ Boolean
-
#execute(symtab) ⇒ void
“execute” the statement by updating the variables in the symbol table.
-
#find_dst_registers(symtab) ⇒ Object
we don’t unroll, but we don’t add the index variable to the symtab, either that will cause any register accesses dependent on the index variable to raise Complex.
-
#find_src_registers(symtab) ⇒ Object
we don’t unroll, but we don’t add the index variable to the symtab, either that will cause any register accesses dependent on the index variable to raise Complex.
-
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
-
#init ⇒ Object
-
#initialize(input, interval, init, condition, update, stmts) ⇒ ForLoopAst
constructor
A new instance of ForLoopAst.
-
#prune(symtab, forced_type: nil) ⇒ Object
-
#reachable_exceptions(symtab, cache = {}) ⇒ Object
-
#reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
-
#return_type(symtab) ⇒ Object
-
#return_value(symtab) ⇒ Integer, ...
Evaluate the compile-time return value of this node, or, if the node does not return (e.g., because it is an IfAst but there is no return on the taken path), execute the node and update the symtab.
-
#return_values(symtab) ⇒ Array<Integer>, Array<Boolean>
Evaluate all possible compile-time return values of this node, or, if the node does not return (e.g., because it is an IfAst but there is no return on a possible path), execute the node and update the symtab.
-
#satisfied?(symtab) ⇒ Boolean
-
#stmts ⇒ Object
-
#to_h ⇒ Object
-
#to_idl ⇒ Object
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
-
#update ⇒ Object
Methods included from Returns
#expected_return_type
Methods included from Executable
#executable?
Methods inherited from AstNode
#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_referenced_csrs, #freeze_tree, #gen_option_adoc, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #nullify_assignments, #pass_find_return_values, #path, #print_ast, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested
Constructor Details
#initialize(input, interval, init, condition, update, stmts) ⇒ ForLoopAst
Returns a new instance of ForLoopAst.
8639
8640
8641
|
# File 'lib/idlc/ast.rb', line 8639
def initialize(input, interval, init, condition, update, stmts)
super(input, interval, [init, condition, update] + stmts)
end
|
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
8781
8782
8783
8784
8785
8786
8787
8788
8789
8790
8791
8792
8793
|
# File 'lib/idlc/ast.rb', line 8781
def self.from_h(yaml, source_mapper)
raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "for_loop_stmt"
input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
interval = interval_from_source_yaml(yaml.fetch("source"))
ForLoopAst.new(
input, interval,
AstNode.from_h(yaml.fetch("init_expr"), source_mapper),
AstNode.from_h(yaml.fetch("condition_expr"), source_mapper),
AstNode.from_h(yaml.fetch("update_expr"), source_mapper),
yaml.fetch("body").map { |s| AstNode.from_h(s, source_mapper) }
)
end
|
Instance Method Details
#condition ⇒ Object
8630
|
# File 'lib/idlc/ast.rb', line 8630
def condition = T.cast(@children.fetch(1), RvalueAst)
|
#const_eval?(symtab) ⇒ Boolean
8619
8620
8621
8622
8623
8624
|
# File 'lib/idlc/ast.rb', line 8619
def const_eval?(symtab)
init.const_eval?(symtab) && \
condition.const_eval?(symtab) && \
update.const_eval?(symtab) && \
stmts.all? { |stmt| stmt.const_eval?(symtab) }
end
|
#execute(symtab) ⇒ void
This method returns an undefined value.
“execute” the statement by updating the variables in the symbol table
8757
|
# File 'lib/idlc/ast.rb', line 8757
def execute(symtab) = return_value(symtab)
|
#find_dst_registers(symtab) ⇒ Object
we don’t unroll, but we don’t add the index variable to the symtab, either that will cause any register accesses dependent on the index variable to raise Complex
66
67
68
69
70
71
72
73
74
75
76
77
|
# File 'lib/idlc/passes/find_src_registers.rb', line 66
def find_dst_registers(symtab)
dsts = init.find_dst_registers(symtab)
dsts += condition.find_dst_registers(symtab)
stmts.each do |stmt|
dsts += stmt.find_dst_registers(symtab)
end
dsts += update.find_dst_registers(symtab)
dsts
end
|
#find_src_registers(symtab) ⇒ Object
we don’t unroll, but we don’t add the index variable to the symtab, either that will cause any register accesses dependent on the index variable to raise Complex
51
52
53
54
55
56
57
58
59
60
61
62
|
# File 'lib/idlc/passes/find_src_registers.rb', line 51
def find_src_registers(symtab)
srcs = init.find_src_registers(symtab)
srcs += condition.find_src_registers(symtab)
stmts.each do |stmt|
srcs += stmt.find_src_registers(symtab)
end
srcs += update.find_src_registers(symtab)
srcs
end
|
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
207
208
209
210
211
212
213
214
|
# File 'lib/idlc/passes/gen_adoc.rb', line 207
def gen_adoc(indent = 0, indent_spaces: 2)
lines = ["#{' ' * indent}for pass:[(]#{init.gen_adoc(0, indent_spaces:)}; #{condition.gen_adoc(0, indent_spaces:)}; #{update.gen_adoc(0, indent_spaces:)}) {"]
stmts.each do |s|
lines << s.gen_adoc(indent + indent_spaces, indent_spaces:)
end
lines << "#{' ' * indent}}"
lines.join("\n")
end
|
#prune(symtab, forced_type: nil) ⇒ Object
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
|
# File 'lib/idlc/passes/prune.rb', line 252
def prune(symtab, forced_type: nil)
symtab.push(self)
symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab)))
stmts.each { |stmt| stmt.nullify_assignments(symtab) }
snapshot = symtab.snapshot_values
begin
new_loop =
ForLoopAst.new(
input, interval,
init.prune(symtab),
condition.prune(symtab),
update.prune(symtab),
stmts.map { |s| s.prune(symtab) }
)
ensure
symtab.restore_values(snapshot)
symtab.pop
end
stmts.each { |stmt| stmt.nullify_assignments(symtab) }
new_loop
end
|
#reachable_exceptions(symtab, cache = {}) ⇒ Object
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
# File 'lib/idlc/passes/reachable_exceptions.rb', line 190
def reachable_exceptions(symtab, cache = {})
symtab.push(self)
begin
symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab)))
mask = init.is_a?(FunctionCallExpressionAst) ? init.reachable_exceptions(symtab, cache) : 0
mask |= condition.reachable_exceptions(symtab, cache) if condition.is_a?(FunctionCallExpressionAst)
mask |= update.reachable_exceptions(symtab, cache) if update.is_a?(FunctionCallExpressionAst)
stmts.each do |stmt|
mask |= stmt.reachable_exceptions(symtab, cache)
end
ensure
symtab.pop
end
mask
end
|
#reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
|
# File 'lib/idlc/passes/reachable_functions.rb', line 205
def reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType))
symtab.push(self)
begin
symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab)))
fns = init.is_a?(FunctionCallExpressionAst) ? init.reachable_functions(symtab, cache) : []
fns.concat(condition.reachable_functions(symtab, cache))
fns.concat(update.reachable_functions(symtab, cache))
stmts.each do |stmt|
fns.concat(stmt.reachable_functions(symtab, cache))
end
ensure
symtab.pop
end
fns
end
|
#return_type(symtab) ⇒ Object
8706
8707
8708
8709
|
# File 'lib/idlc/ast.rb', line 8706
def return_type(symtab)
expected_return_type(symtab)
end
|
#return_value(symtab) ⇒ Integer, ...
Evaluate the compile-time return value of this node, or, if the node does not return (e.g., because it is an IfAst but there is no return on the taken path), execute the node and update the symtab
8673
8674
8675
8676
8677
8678
8679
8680
8681
8682
8683
8684
8685
8686
8687
8688
8689
8690
8691
8692
8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
8703
|
# File 'lib/idlc/ast.rb', line 8673
def return_value(symtab)
symtab.push(self)
begin
value_result = value_try do
init.execute(symtab)
while condition.value(symtab)
stmts.each do |s|
if s.is_a?(Returns)
v = s.return_value(symtab)
unless v.nil?
return v
end
else
unless s.is_a?(ImplicationStatementAst)
s.execute(symtab)
end
end
end
update.execute(symtab)
end
end
value_else(value_result) do
value_error ""
end
ensure
symtab.pop
end
nil
end
|
#return_values(symtab) ⇒ Array<Integer>, Array<Boolean>
Evaluate all possible compile-time return values of this node, or, if the node does not return (e.g., because it is an IfAst but there is no return on a possible path), execute the node and update the symtab
8712
8713
8714
8715
8716
8717
8718
8719
8720
8721
8722
8723
8724
8725
8726
8727
8728
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
8746
8747
8748
8749
8750
8751
8752
8753
8754
|
# File 'lib/idlc/ast.rb', line 8712
def return_values(symtab)
value_result = value_try do
return [return_value(symtab)]
end
value_else(value_result) do
values = T.let([], T::Array[ValueRbType])
symtab.push(self)
begin
value_result = value_try do
init.execute(symtab)
while condition.value(symtab)
stmts.each do |s|
if s.is_a?(Returns)
value_result = value_try do
v = s.return_value(symtab)
unless v.nil?
return values.push(v).uniq
end
end
value_else(value_result) do
values += s.return_values(symtab)
end
else
unless s.is_a?(ImplicationStatementAst)
s.execute(symtab)
end
end
end
update.execute(symtab)
end
:ok
end
ensure
symtab.pop
end
values.uniq
end
end
|
#satisfied?(symtab) ⇒ Boolean
8656
8657
8658
8659
8660
8661
8662
8663
8664
8665
8666
8667
8668
8669
8670
|
# File 'lib/idlc/ast.rb', line 8656
def satisfied?(symtab)
symtab.push(self)
begin
init.execute(symtab)
while condition.value(symtab)
stmts.each do |s|
return false unless T.cast(s, ImplicationStatementAst).satisfied?(symtab)
end
update.execute(symtab)
end
return true
ensure
symtab.pop
end
end
|
#stmts ⇒ Object
8637
|
# File 'lib/idlc/ast.rb', line 8637
def stmts = T.cast(@children[3..], T::Array[StmtType])
|
#to_h ⇒ Object
8771
8772
8773
8774
8775
8776
8777
8778
|
# File 'lib/idlc/ast.rb', line 8771
def to_h = {
"kind" => "for_loop_stmt",
"init_expr" => init.to_h,
"condition_expr" => condition.to_h,
"update_expr" => update.to_h,
"body" => stmts.map(&:to_h),
"source" => source_yaml
}
|
#to_idl ⇒ Object
8761
8762
8763
8764
8765
8766
8767
8768
|
# File 'lib/idlc/ast.rb', line 8761
def to_idl
idl = "for (#{init.to_idl}; #{condition.to_idl}; #{update.to_idl}) {"
stmts.each do |s|
idl << s.to_idl
end
idl << "}"
idl
end
|
#type_check(symtab, strict:) ⇒ void
This method returns an undefined value.
type check this node and all children
Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError
8644
8645
8646
8647
8648
8649
8650
8651
8652
8653
|
# File 'lib/idlc/ast.rb', line 8644
def type_check(symtab, strict:)
symtab.push(self)
init.type_check(symtab, strict:)
condition.type_check(symtab, strict:)
update.type_check(symtab, strict:)
stmts.each { |stmt| stmt.type_check(symtab, strict:) }
symtab.pop
end
|
#update ⇒ Object
8633
|
# File 'lib/idlc/ast.rb', line 8633
def update = T.cast(@children.fetch(2), ExecutableAst)
|