Class: Idl::MultiVariableAssignmentAst
- Includes:
- Executable
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb
Overview
represents assignment of multiple variable from a function call that returns multiple values
for example:
(match_result, cfg) = pmp_match<access_size>(paddr);
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
- #const_eval?(symtab) ⇒ Boolean
-
#execute(symtab) ⇒ void
“execute” the statement by updating the variables in the symbol table.
- #function_call ⇒ Object
- #gen_adoc(indent, indent_spaces: 2) ⇒ Object
-
#initialize(input, interval, variables, function_call) ⇒ MultiVariableAssignmentAst
constructor
A new instance of MultiVariableAssignmentAst.
- #nullify_assignments(symtab) ⇒ Object
- #prune(symtab, forced_type: nil) ⇒ Object
- #rhs ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
- #variables ⇒ Object
-
#vars ⇒ Array<AstNode>
The variables being assigned, in order.
Methods included from Executable
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, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #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, variables, function_call) ⇒ MultiVariableAssignmentAst
Returns a new instance of MultiVariableAssignmentAst.
3449 3450 3451 |
# File 'lib/idlc/ast.rb', line 3449 def initialize(input, interval, variables, function_call) super(input, interval, variables + [function_call]) end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 |
# File 'lib/idlc/ast.rb', line 3530 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "multi_var_assignment" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) MultiVariableAssignmentAst.new( input, interval, yaml.fetch("assignments").map { |a| AstNode.from_h(a, source_mapper) }, T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst) ) end |
Instance Method Details
#const_eval?(symtab) ⇒ Boolean
3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 |
# File 'lib/idlc/ast.rb', line 3431 def const_eval?(symtab) func_is_const_eval = function_call.const_eval?(symtab) everything_is_const_eval = func_is_const_eval variables.each do |variable| var = symtab.get(variable.name) type_error "#{var} was not declared" if var.nil? everything_is_const_eval = false unless var.const_eval? var.const_incompatible! unless func_is_const_eval end func_is_const_eval end |
#execute(symtab) ⇒ void
This method returns an undefined value.
“execute” the statement by updating the variables in the symbol table
3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 |
# File 'lib/idlc/ast.rb', line 3494 def execute(symtab) value_result = value_try do values = function_call.execute(symtab) i = 0 variables.each do |v| next if v.type(symtab).global? var = symtab.get(v.text_value) internal_error "call type check" if var.nil? var.value = values[i] i += 1 end end value_else(value_result) do variables.each do |v| symtab.get(v.text_value).value = nil end value_error "value of right-hand side of multi-variable assignment is unknown" end end |
#function_call ⇒ Object
3447 |
# File 'lib/idlc/ast.rb', line 3447 def function_call = @children.last |
#gen_adoc(indent, indent_spaces: 2) ⇒ Object
76 77 78 |
# File 'lib/idlc/passes/gen_adoc.rb', line 76 def gen_adoc(indent, indent_spaces: 2) "#{' ' * indent}(#{variables.map { |v| v.gen_adoc(0, indent_spaces:) }.join(', ')} = #{function_call.gen_adoc(0, indent_spaces:)})" end |
#nullify_assignments(symtab) ⇒ Object
185 186 187 188 189 190 |
# File 'lib/idlc/passes/prune.rb', line 185 def nullify_assignments(symtab) variables.each do |v| sym = symtab.get(v.text_value) sym.value = nil unless sym.nil? end end |
#prune(symtab, forced_type: nil) ⇒ Object
883 884 885 886 887 888 889 890 891 892 893 894 |
# File 'lib/idlc/passes/prune.rb', line 883 def prune(symtab, forced_type: nil) new_ast = MultiVariableAssignmentAst.new( input, interval, variables.map(&:dup), function_call.prune(symtab) ) value_try do new_ast.execute(symtab) end # value_else: execute already sets nil on failure, nothing more to do new_ast end |
#rhs ⇒ Object
3458 3459 3460 |
# File 'lib/idlc/ast.rb', line 3458 def rhs function_call end |
#to_h ⇒ Object
3522 3523 3524 3525 3526 3527 |
# File 'lib/idlc/ast.rb', line 3522 def to_h = { "kind" => "multi_var_assignment", "assignments" => variables.map(&:to_h), "value" => function_call.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
3519 |
# File 'lib/idlc/ast.rb', line 3519 def to_idl = "(#{variables.map(&:to_idl).join(', ')}) = #{function_call.to_idl}" |
#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
3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 |
# File 'lib/idlc/ast.rb', line 3463 def type_check(symtab, strict:) function_call.type_check(symtab, strict:) variables.each { |var| var.type_check(symtab, strict:) } type_error "Assigning value to a constant" if variables.any? { |v| v.type(symtab).const? } type_error "Function '#{function_call.name}' has no return type" if function_call.type(symtab).nil? unless function_call.type(symtab).kind == :tuple type_error "Function '#{function_call.name}' only returns 1 variable" end if function_call.type(symtab).tuple_types.size != vars.size type_error "function '#{function_call.name}' returns #{function_call.type(symtab).tuple_types.size} arguments, but #{variables.size} were specified" end function_call.type(symtab).tuple_types.each_index do |i| next if variables[i].is_a?(DontCareLvalueAst) raise "Implementation error" if variables[i].is_a?(DontCareReturnAst) var = symtab.get(variables[i].text_value) type_error "No symbol named '#{variables[i].text_value}'" if var.nil? internal_error "Cannot determine type of #{variables[i].text_value}" unless var.respond_to?(:type) unless var.type.convertable_to?(function_call.type(symtab).tuple_types[i]) type_error "'#{function_call.name}' expecting a #{function_call.type(symtab).tuple_types[i]} in argument #{i}, but was given #{var.type(symtab)}" end end end |
#variables ⇒ Object
3446 |
# File 'lib/idlc/ast.rb', line 3446 def variables = @children[0..-2] |
#vars ⇒ Array<AstNode>
Returns The variables being assigned, in order.
3454 3455 3456 |
# File 'lib/idlc/ast.rb', line 3454 def vars variables end |