Class: Idl::VariableDeclarationWithInitializationAst
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
#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
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
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
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
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_size ⇒ Object
3861
|
# File 'lib/idlc/ast.rb', line 3861
def ary_size = @children[3].nil? ? nil : T.cast(@children[3], RvalueAst)
|
#const_eval?(symtab) ⇒ 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
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
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
|
#id ⇒ Object
3867
|
# File 'lib/idlc/ast.rb', line 3867
def id = lhs.text_value
|
#lhs ⇒ Object
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_global ⇒ Object
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)
VariableDeclarationWithInitializationAst.new(
input, interval,
type_name.dup,
lhs.dup,
ary_size&.prune(symtab),
rhs.prune(symtab),
@for_iter_var
)
end
|
#rhs ⇒ Object
3864
|
# File 'lib/idlc/ast.rb', line 3864
def rhs = T.cast(@children[2], RvalueAst)
|
#to_h ⇒ Object
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_idl ⇒ Object
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
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?
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:)
return if rhs.type(symtab).convertable_to?(decl_type)
type_error "Incompatible type (#{decl_type}, #{rhs.type(symtab)}) in assignment"
end
|
#type_name ⇒ Object
3855
|
# File 'lib/idlc/ast.rb', line 3855
def type_name = T.cast(@children[0], TypeNameAst)
|