Class: Idl::VariableDeclarationAst

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

Overview

represents a single variable declaration (without assignment)

for example:

Bits<64> doubleword
Boolean has_property

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 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, id, ary_size) ⇒ VariableDeclarationAst

Returns a new instance of VariableDeclarationAst.



3679
3680
3681
3682
3683
3684
3685
3686
3687
# File 'lib/idlc/ast.rb', line 3679

def initialize(input, interval, type_name, id, ary_size)
  if ary_size.nil?
    super(input, interval, [type_name, id])
  else
    super(input, interval, [type_name, id, ary_size])
  end

  @global = false
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
# File 'lib/idlc/ast.rb', line 3788

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

  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")
    VariableDeclarationAst.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)
    )
  else
    VariableDeclarationAst.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
    )
  end
end

Instance Method Details

#add_symbol(symtab) ⇒ Object



3755
3756
3757
3758
3759
3760
3761
3762
3763
# File 'lib/idlc/ast.rb', line 3755

def add_symbol(symtab)
  if @global
    # fill global with nil to prevent its use in compile-time evaluation
    symtab.add!(id.text_value, Var.new(id.text_value, decl_type(symtab), nil))
  else
    type_error "No Type '#{type_name.text_value}'" if decl_type(symtab).nil?
    symtab.add(id.text_value, Var.new(id.text_value, decl_type(symtab), T.must(decl_type(symtab)).default))
  end
end

#ary_sizeObject



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

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

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


3653
3654
3655
3656
# File 'lib/idlc/ast.rb', line 3653

def const_eval?(symtab)
  add_symbol(symtab)
  true
end

#decl_type(symtab) ⇒ Object



3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
# File 'lib/idlc/ast.rb', line 3695

def decl_type(symtab)
  dtype = type_name.type(symtab)

  return nil if dtype.nil?

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

  dtype = Type.new(:enum_ref, enum_class: T.cast(dtype, EnumerationType), qualifiers:) if dtype.kind == :enum

  # dtype = dtype.clone.qualify(q.text_value.to_sym) unless q.empty?

  unless ary_size.nil?
    value_result = value_try do
      dtype = Type.new(:array, width: T.cast(T.must(ary_size).value(symtab), Integer), sub_type: dtype, qualifiers:)
    end
    value_else(value_result) do
      dtype = Type.new(:array, width: :unknown, sub_type: dtype, qualifiers:)
    end
  end

  dtype
end

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



179
180
181
# File 'lib/idlc/passes/gen_adoc.rb', line 179

def gen_adoc(indent = 0, indent_spaces: 2)
  "#{' ' * indent}#{type_name.gen_adoc(0, indent_spaces:)} #{id.gen_adoc(0, indent_spaces:)}"
end

#idObject



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

def id = T.cast(children.fetch(1), IdAst)

#make_globalObject



3690
3691
3692
# File 'lib/idlc/ast.rb', line 3690

def make_global
  @global = true
end

#nameObject



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

def name = id.text_value

#prune(symtab, forced_type: nil) ⇒ Object



947
948
949
950
# File 'lib/idlc/passes/prune.rb', line 947

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

#to_hObject



3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
# File 'lib/idlc/ast.rb', line 3776

def to_h = {
  "kind" => "var_decl",
  "type" => ary_size.nil? ? type_name.to_h : {
    "kind" => "array_decl",
    "array_size" => ary_size.to_h,
    "element_type" => type_name.to_h
  },
  "name" => id.to_h,
  "source" => source_yaml
}

#to_idlObject



3767
3768
3769
3770
3771
3772
3773
# File 'lib/idlc/ast.rb', line 3767

def to_idl
  if ary_size.nil?
    "#{type_name.to_idl} #{id.to_idl}"
  else
    "#{type_name.to_idl} #{id.to_idl}[#{T.must(ary_size).to_idl}]"
  end
end

#type(symtab) ⇒ Object



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

def type(symtab) = decl_type(symtab)

#type_check(symtab, add_sym: true, strict:, is_function_arg: false) ⇒ 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:



3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
# File 'lib/idlc/ast.rb', line 3723

def type_check(symtab, add_sym: true, strict:, is_function_arg: false)
  type_name.type_check(symtab, strict:)
  dtype = type_name.type(symtab)

  type_error "No type '#{type_name.text_value}'" if dtype.nil?

  # Constants must be initialized at declaration, unless they are function arguments
  # (function arguments are initialized when the function is called)
  if !is_function_arg && id.text_value[0] == T.must(id.text_value[0]).upcase
    type_error "Constants must be initialized at declaration"
  end

  type_error "Cannot use reserved word '#{id.text_value}' as variable name" if ReservedWords::RESERVED.include?(id.text_value)

  unless ary_size.nil?
    T.must(ary_size).type_check(symtab, strict:)
    value_result = value_try do
      T.must(ary_size).value(symtab)
    end
    value_else(value_result) do
      # it's ok that we don't know the value yet, as long as the value is a const
      type_error "Array size (#{T.must(ary_size).text_value}) must be a constant" unless T.must(ary_size).type(symtab).const?
    end
  end

  add_symbol(symtab) if add_sym

  id.type_check(symtab, strict:)
end

#type_nameObject



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

def type_name = T.cast(children.fetch(0), TypeNameAst)