Class: Idl::FieldAssignmentAst
- 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 a bitfield or struct assignment
for example:
Sv39PageTableEntry entry;
entry.PPN = 0
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.
- #field_name ⇒ Object
- #gen_adoc(indent, indent_spaces: 2) ⇒ Object
- #id ⇒ Object
-
#initialize(input, interval, id, field_name, rhs) ⇒ FieldAssignmentAst
constructor
A new instance of FieldAssignmentAst.
- #nullify_assignments(symtab) ⇒ Object
- #prune(symtab, forced_type: nil) ⇒ Object
- #rhs ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
-
#type(symtab) ⇒ Type
Given a specific symbol table, return the type of this node.
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
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, id, field_name, rhs) ⇒ FieldAssignmentAst
Returns a new instance of FieldAssignmentAst.
3250 3251 3252 3253 |
# File 'lib/idlc/ast.rb', line 3250 def initialize(input, interval, id, field_name, rhs) super(input, interval, [id, rhs]) @field_name = field_name end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 |
# File 'lib/idlc/ast.rb', line 3337 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "field_assignment" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) FieldAssignmentAst.new( input, interval, T.cast(AstNode.from_h(yaml.fetch("var"), source_mapper), IdAst), yaml.fetch("field_name"), T.cast(AstNode.from_h(yaml.fetch("value"), source_mapper), RvalueAst) ) end |
Instance Method Details
#const_eval?(symtab) ⇒ Boolean
3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 |
# File 'lib/idlc/ast.rb', line 3235 def const_eval?(symtab) var = symtab.get(id.name) type_error "#{id.name} is not declared!" if var.nil? return false if !var.const_eval? 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
3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 |
# File 'lib/idlc/ast.rb', line 3295 def execute(symtab) var = symtab.get(id.name) type_error "#{id.name} has not been declared" if var.nil? if var.type.kind == :bitfield bitfield_val = id.value(symtab) range = var.type.range(@field_name) rhs_value = T.cast(rhs.value(symtab), Integer) rhs_value_trunc = rhs_value & ((1 << range.size) - 1) # zero out the field bitfield_val &= ~(((1 << range.size) - 1) << range.first) bitfield_val |= rhs_value_trunc << range.first var.value = bitfield_val elsif var.type.kind == :struct struct_val = id.value(symtab) value_result = value_try do struct_val[@field_name] = rhs.value(symtab) end value_else(value_result) do struct_val[@field_name] = nil value_error "" end else value_error "TODO: Field assignment execution" end end |
#field_name ⇒ Object
3232 |
# File 'lib/idlc/ast.rb', line 3232 def field_name = @field_name |
#gen_adoc(indent, indent_spaces: 2) ⇒ Object
97 98 99 |
# File 'lib/idlc/passes/gen_adoc.rb', line 97 def gen_adoc(indent, indent_spaces: 2) "#{id.gen_adoc(0, indent_spaces:)}.#{@field_name} = #{rhs.gen_adoc(0, indent_spaces:)}" end |
#id ⇒ Object
3226 |
# File 'lib/idlc/ast.rb', line 3226 def id = T.cast(@children.fetch(0), IdAst) |
#nullify_assignments(symtab) ⇒ Object
179 180 181 182 |
# File 'lib/idlc/passes/prune.rb', line 179 def nullify_assignments(symtab) var = symtab.get(id.name) var.value = nil unless var.nil? end |
#prune(symtab, forced_type: nil) ⇒ Object
931 932 933 934 935 936 937 938 939 940 941 942 943 |
# File 'lib/idlc/passes/prune.rb', line 931 def prune(symtab, forced_type: nil) new_ast = FieldAssignmentAst.new( input, interval, id.dup, @field_name, rhs.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
3229 |
# File 'lib/idlc/ast.rb', line 3229 def rhs = T.cast(@children.fetch(1), RvalueAst) |
#to_h ⇒ Object
3328 3329 3330 3331 3332 3333 3334 |
# File 'lib/idlc/ast.rb', line 3328 def to_h = { "kind" => "field_assignment", "var" => id.to_h, "field_name" => @field_name, "value" => rhs.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
3325 |
# File 'lib/idlc/ast.rb', line 3325 def to_idl = "#{id.to_idl}.#{@field_name} = #{rhs.to_idl}" |
#type(symtab) ⇒ Type
Given a specific symbol table, return the type of this node.
Should not be called until #type_check is called with the same arguments
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 |
# File 'lib/idlc/ast.rb', line 3256 def type(symtab) var = symtab.get(id.name) type_error "#{id.name} has not been declared" if var.nil? if var.type.kind == :bitfield Type.new(:bits, width: var.type.range(@field_name).size) elsif var.type.kind == :struct var.type.member_type(@field_name) else internal_error "huh? #{id.text_value} #{var.type.kind}" 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
3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 |
# File 'lib/idlc/ast.rb', line 3270 def type_check(symtab, strict:) id.type_check(symtab, strict:) var = symtab.get(id.name) type_error "#{id.name} has not been declared" if var.nil? if var.type.kind == :bitfield internal_error "#{id.name} Not a BitfieldType (is a #{var.type})" unless var.type.respond_to?(:field_names) unless var.type.field_names.include?(@field_name) type_error "#{@field_name} is not a member of #{var.type}" end elsif var.type.kind == :struct type_error "#{@field_name} is not a member of #{var.type}" unless var.type.member?(@field_name) else type_error "#{id.name} is not a bitfield or struct (is #{var.type})" end type_error "Cannot write const variable" if var.type.const? rhs.type_check(symtab, strict:) return if rhs.type(symtab).convertable_to?(type(symtab)) type_error "Incompatible type in assignment (#{type(symtab)}, #{rhs.type(symtab)})" end |