Class: Idl::VariableDeclarationWithInitializationAst

Inherits:
AstNode
  • Object
show all
Includes:
Declaration, Executable
Defined in:
lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb

Overview

represents a single variable declaration with initialization

for example:

Bits<64> doubleword = 64'hdeadbeef
Boolean has_property = true

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

Methods included from Declaration

#declaration?

Methods included from Executable

#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, #nullify_assignments, #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, type_name_ast, var_write_ast, ary_size, rval_ast, is_for_loop_iteration_var) ⇒ VariableDeclarationWithInitializationAst

Returns a new instance of VariableDeclarationWithInitializationAst.



3880
3881
3882
3883
3884
3885
3886
3887
3888
# File 'lib/idlc/ast.rb', line 3880

def initialize(input, interval, type_name_ast, var_write_ast, ary_size, rval_ast, is_for_loop_iteration_var)
  if ary_size.nil?
    super(input, interval, [type_name_ast, var_write_ast, rval_ast])
  else
    super(input, interval, [type_name_ast, var_write_ast, rval_ast, ary_size])
  end
  @global = false
  @for_iter_var = is_for_loop_iteration_var
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
# File 'lib/idlc/ast.rb', line 4024

def self.from_h(yaml, source_mapper)
  raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "var_decl_init"

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  if yaml.fetch("type").key?("array_size")
    VariableDeclarationWithInitializationAst.new(
      input, interval,
      T.cast(AstNode.from_h(yaml.fetch("type").fetch("element_type"), source_mapper), TypeNameAst),
      T.cast(AstNode.from_h(yaml.fetch("name"), source_mapper), IdAst),
      T.cast(AstNode.from_h(yaml.fetch("type").fetch("array_size"), source_mapper), RvalueAst),
      T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst),
      yaml.fetch("in_for_loop")
    )
  else
    VariableDeclarationWithInitializationAst.new(
      input, interval,
      T.cast(AstNode.from_h(yaml.fetch("type"), source_mapper), TypeNameAst),
      T.cast(AstNode.from_h(yaml.fetch("name"), source_mapper), IdAst),
      nil,
      T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst),
      yaml.fetch("in_for_loop")
    )
  end
end

Instance Method Details

#add_symbol(symtab) ⇒ Object

Add symbol(s) at the outermost scope of the symbol table

Parameters:

  • symtab (SymbolTable)

    Symbol table at the scope that the symbol(s) will be inserted



3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
# File 'lib/idlc/ast.rb', line 3954

def add_symbol(symtab)
  if @global
    if lhs.text_value[0] == T.must(lhs.text_value[0]).upcase
      # const, add the value if it's known
      value_result = value_try do
        symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs.value(symtab), for_loop_iter: @for_iter_var))
      end
      value_else(value_result) do
        symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), for_loop_iter: @for_iter_var))
      end
    else
      # mutable globals never have a compile-time value
      symtab.add!(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), for_loop_iter: @for_iter_var))
    end
  else
    value_result = value_try do
      if @for_iter_var
        # don't add the value, because it will change across iterations
        symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), for_loop_iter: @for_iter_var))
      else
        symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs.value(symtab), for_loop_iter: @for_iter_var))
      end
    end
    value_else(value_result) do
      symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), for_loop_iter: @for_iter_var))
    end
  end
end

#ary_sizeObject



3861
# File 'lib/idlc/ast.rb', line 3861

def ary_size = @children[3].nil? ? nil : T.cast(@children[3], RvalueAst)

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
# File 'lib/idlc/ast.rb', line 3843

def const_eval?(symtab)
  var = Var.new(lhs.text_value, lhs_type(symtab))
  symtab.add(lhs.text_value, var)
  if rhs.const_eval?(symtab)
    true
  else
    var.const_incompatible!
    false
  end
end

#execute(symtab) ⇒ void

This method returns an undefined value.

“execute” the statement by updating the variables in the symbol table

Parameters:

  • symtab (SymbolTable)

    The symbol table for the context

Raises:

  • ValueError if some part of the statement cannot be executed at compile time



3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
# File 'lib/idlc/ast.rb', line 3984

def execute(symtab)
  value_error "TODO: Array declaration" unless ary_size.nil?
  rhs_value = T.let(nil, T.nilable(ValueRbType))
  return if @global # never executed at compile time

  value_result = value_try do
    rhs_value = rhs.value(symtab)
  end
  value_else(value_result) do
    symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), nil, for_loop_iter: @for_iter_var))
    value_error "value of right-hand side of variable initialization is unknown"
  end
  symtab.add(lhs.text_value, Var.new(lhs.text_value, lhs_type(symtab), rhs_value))
end

#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object



224
225
226
227
228
229
230
# File 'lib/idlc/passes/gen_adoc.rb', line 224

def gen_adoc(indent = 0, indent_spaces: 2)
  if ary_size.nil?
    "#{' ' * indent}#{type_name.gen_adoc(0, indent_spaces:)} #{lhs.gen_adoc(0, indent_spaces:)} = #{rhs.gen_adoc(0, indent_spaces:)}"
  else
    "#{' ' * indent}#{type_name.gen_adoc(0, indent_spaces:)} #{lhs.gen_adoc(0, indent_spaces:)}[#{ary_size.gen_adoc(0, indent_spaces:)}] = #{rhs.gen_adoc(0, indent_spaces:)}"
  end
end

#idObject



3867
# File 'lib/idlc/ast.rb', line 3867

def id = lhs.text_value

#lhsObject



3858
# File 'lib/idlc/ast.rb', line 3858

def lhs = T.cast(@children[1], IdAst)

#lhs_type(symtab) ⇒ Object



3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
# File 'lib/idlc/ast.rb', line 3894

def lhs_type(symtab)
  decl_type = type_name.type(symtab).clone
  type_error "No type '#{type_name.text_value}' on line #{lineno}" if decl_type.nil?

  qualifiers = []
  qualifiers << :const if T.must(lhs.text_value[0]).upcase == lhs.text_value[0]
  qualifiers << :global if @global

  decl_type = Type.new(:enum_ref, enum_class: decl_type) if decl_type.kind == :enum

  qualifiers.each do |q|
    decl_type.qualify(q)
  end

  unless ary_size.nil?
    value_result = value_try do
      decl_type = Type.new(:array, sub_type: decl_type, width: T.cast(T.must(ary_size).value(symtab), Integer), qualifiers:)
    end
    value_else(value_result) do
      type_error "Array size must be known at compile time"
    end
  end

  decl_type
end

#make_globalObject



3890
3891
3892
# File 'lib/idlc/ast.rb', line 3890

def make_global
  @global = true
end

#prune(symtab, forced_type: nil) ⇒ Object



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/idlc/passes/prune.rb', line 227

def prune(symtab, forced_type: nil)
  add_symbol(symtab)

  # do we want to remove a constant? If so, need to add a prune for IdAst that
  # spits out a literal
  #
  # if lhs.const?
  #   value_try do
  #     rhs.value(symtab)
  #     # rhs value is known, and variable is const. it can be removed
  #     return NoopAst.new
  #   end
  # end

  VariableDeclarationWithInitializationAst.new(
    input, interval,
    type_name.dup,
    lhs.dup,
    ary_size&.prune(symtab),
    rhs.prune(symtab),
    @for_iter_var
  )
end

#rhsObject



3864
# File 'lib/idlc/ast.rb', line 3864

def rhs = T.cast(@children[2], RvalueAst)

#to_hObject



4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
# File 'lib/idlc/ast.rb', line 4010

def to_h = {
  "kind" => "var_decl_init",
  "type" => ary_size.nil? ? type_name.to_h : {
    "kind" => "array_decl",
    "array_size" => ary_size.to_h,
    "element_type" => type_name.to_h
  },
  "name" => lhs.to_h,
  "value" => rhs.to_h,
  "in_for_loop" => @for_iter_var,
  "source" => source_yaml
}

#to_idlObject



4001
4002
4003
4004
4005
4006
4007
# File 'lib/idlc/ast.rb', line 4001

def to_idl
  if ary_size.nil?
    "#{type_name.to_idl} #{lhs.to_idl} = #{rhs.to_idl}"
  else
    "#{type_name.to_idl} #{lhs.to_idl}[#{T.must(ary_size).to_idl}] = #{rhs.to_idl}"
  end
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

Parameters:

Raises:



3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
# File 'lib/idlc/ast.rb', line 3921

def type_check(symtab, strict:)
  rhs.type_check(symtab, strict:)

  type_name.type_check(symtab, strict:)

  ary_size&.type_check(symtab, strict:)

  decl_type = lhs_type(symtab)

  if decl_type.const?
    # this is a constant; ensure we are assigning a constant value
    value_result = value_try do
      symtab.add(lhs.text_value, Var.new(lhs.text_value, decl_type.clone, rhs.value(symtab), for_loop_iter: @for_iter_var))
    end
    value_else(value_result) do
      unless rhs.type(symtab).const?
        type_error "Declaring constant (#{lhs.name}) with a non-constant value (#{rhs.text_value})"
      end
      symtab.add(lhs.text_value, Var.new(lhs.text_value, decl_type.clone, for_loop_iter: @for_iter_var))
    end
  else
    symtab.add(lhs.text_value, Var.new(lhs.text_value, decl_type.clone, for_loop_iter: @for_iter_var))
  end

  lhs.type_check(symtab, strict:)

  # now check that the assignment is compatible
  return if rhs.type(symtab).convertable_to?(decl_type)

  type_error "Incompatible type (#{decl_type}, #{rhs.type(symtab)}) in assignment"
end

#type_nameObject



3855
# File 'lib/idlc/ast.rb', line 3855

def type_name = T.cast(@children[0], TypeNameAst)