Class: Idl::ConditionalStatementAst
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/reachable_functions.rb,
lib/idlc/passes/reachable_exceptions.rb
Overview
represents a predicated simple statement
for example:
a = 2 if condition;
Constant Summary
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
- #action ⇒ Object
- #condition ⇒ Object
- #const_eval?(symtab) ⇒ Boolean
-
#execute(symtab) ⇒ void
“execute” the statement by updating the variables in the symbol table.
- #gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
-
#initialize(input, interval, action, condition) ⇒ ConditionalStatementAst
constructor
A new instance of ConditionalStatementAst.
- #prune(symtab, forced_type: nil) ⇒ Object
- #reachable_exceptions(symtab, cache = {}) ⇒ Object
- #reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
Methods inherited from AstNode
#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_dst_registers, #find_referenced_csrs, #find_src_registers, #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, action, condition) ⇒ ConditionalStatementAst
Returns a new instance of ConditionalStatementAst.
6649 6650 6651 |
# File 'lib/idlc/ast.rb', line 6649 def initialize(input, interval, action, condition) super(input, interval, [action, condition]) end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 |
# File 'lib/idlc/ast.rb', line 6693 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "conditional_stmt" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) ConditionalStatementAst.new( input, interval, AstNode.from_h(yaml.fetch("expr"), source_mapper), AstNode.from_h(yaml.fetch("condition"), source_mapper) ) end |
Instance Method Details
#action ⇒ Object
6643 |
# File 'lib/idlc/ast.rb', line 6643 def action = @children[0] |
#condition ⇒ Object
6644 |
# File 'lib/idlc/ast.rb', line 6644 def condition = @children[1] |
#const_eval?(symtab) ⇒ Boolean
6647 |
# File 'lib/idlc/ast.rb', line 6647 def const_eval?(symtab) = action.const_eval?(symtab) && condition.const_eval?(symtab) |
#execute(symtab) ⇒ void
This method returns an undefined value.
“execute” the statement by updating the variables in the symbol table
6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 |
# File 'lib/idlc/ast.rb', line 6663 def execute(symtab) value_result = value_try do cond = condition.value(symtab) if (cond) action.execute(symtab) end end value_else(value_result) do # condition is unknown; nullify any variables the action would assign action.nullify_assignments(symtab) value_error "" end end |
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
288 289 290 |
# File 'lib/idlc/passes/gen_adoc.rb', line 288 def gen_adoc(indent = 0, indent_spaces: 2) "#{' ' * indent}#{action.gen_adoc(0, indent_spaces:)} if (#{condition.gen_adoc(0, indent_spaces:)});" end |
#prune(symtab, forced_type: nil) ⇒ Object
611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 |
# File 'lib/idlc/passes/prune.rb', line 611 def prune(symtab, forced_type: nil) value_result = value_try do if condition.value(symtab) pruned_action = action.prune(symtab) pruned_action.add_symbol(symtab) if pruned_action.declaration? value_result = value_try do pruned_action.execute(symtab) if pruned_action.executable? end return StatementAst.new(input, interval, pruned_action) else return NoopAst.new end end value_else(value_result) do # condition not known pruned_action = action.prune(symtab) pruned_action.add_symbol(symtab) if pruned_action.declaration? value_result = value_try do pruned_action.execute(symtab) if pruned_action.executable? end # Condition is unknown, so the assignment may not have run; nullify to prevent leakage pruned_action.nullify_assignments(symtab) ConditionalStatementAst.new(input, interval, pruned_action, condition.prune(symtab)) end end |
#reachable_exceptions(symtab, cache = {}) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/idlc/passes/reachable_exceptions.rb', line 159 def reachable_exceptions(symtab, cache = {}) mask = 0 value_result = value_try do mask |= condition.reachable_exceptions(symtab, cache) if condition.value(symtab) mask |= action.reachable_exceptions(symtab, cache) action.add_symbol(symtab) if action.declaration? if action.executable? value_result = value_try do action.execute(symtab) end end end end value_else(value_result) do mask = 0 # condition not known mask |= condition.reachable_exceptions(symtab, cache) mask |= action.reachable_exceptions(symtab, cache) action.add_symbol(symtab) if action.declaration? if action.executable? value_result = value_try do action.execute(symtab) end end end mask end |
#reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/idlc/passes/reachable_functions.rb', line 181 def reachable_functions(symtab, cache = T.let({}, ReachableFunctionCacheType)) fns = condition.is_a?(FunctionCallExpressionAst) ? condition.reachable_functions(symtab, cache) : [] value_result = value_try do if condition.value(symtab) fns.concat action.reachable_functions(symtab, cache) # no need to execute action (return) end end value_else(value_result) do # condition not known fns = fns.concat action.reachable_functions(symtab, cache) end fns end |
#to_h ⇒ Object
6685 6686 6687 6688 6689 6690 |
# File 'lib/idlc/ast.rb', line 6685 def to_h = { "kind" => "conditional_stmt", "condition" => condition.to_h, "expr" => action.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
6680 6681 6682 |
# File 'lib/idlc/ast.rb', line 6680 def to_idl "#{action.to_idl} if (#{condition.to_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
6654 6655 6656 6657 6658 6659 6660 |
# File 'lib/idlc/ast.rb', line 6654 def type_check(symtab, strict:) action.type_check(symtab, strict:) type_error "Cannot declare from a conditional statement" if action.declaration? condition.type_check(symtab, strict:) type_error "condition is not boolean" unless condition.type(symtab).convertable_to?(:boolean) end |