Class: Idl::ConcatenationExpressionAst

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

Overview

represents a concatenation expression

for example:

{1'b0, 5'd3}

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 Rvalue

#max_value, #min_value, #truncate, #values

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, #initialize, #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

This class inherits a constructor from Idl::AstNode

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



5558
5559
5560
5561
5562
5563
5564
5565
5566
5567
# File 'lib/idlc/ast.rb', line 5558

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

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  ConcatenationExpressionAst.new(
    input, interval,
    yaml.fetch("exprs").map { |v| AstNode.from_h(v, source_mapper) }
  )
end

Instance Method Details

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


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

def const_eval?(symtab) = expressions.all? { |e| e.const_eval?(symtab) }

#expressionsObject



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

def expressions = @children

#gen_adoc(indent, indent_spaces: 2) ⇒ Object



102
103
104
# File 'lib/idlc/passes/gen_adoc.rb', line 102

def gen_adoc(indent, indent_spaces: 2)
  "#{' ' * indent}{#{expressions.map { |e| e.gen_adoc(0, indent_spaces:) }.join(', ')}}"
end

#prune(symtab, forced_type: nil) ⇒ Object



640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
# File 'lib/idlc/passes/prune.rb', line 640

def prune(symtab, forced_type: nil)
  value_result = value_try do
    v = value(symtab)
    return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
  end
  value_else(value_result) do
    c = ConcatenationExpressionAst.new(
      input, interval, @children.map { |c| c.prune(symtab) }
    )
    if forced_type
      if forced_type.width < type(symtab).width
        c = AryRangeAccessAst.new(
          input, interval, c, PruneHelpers.create_int_literal(forced_type.width - 1), create_int_literal(0)
        )
      elsif forced_type.width > type(symtab).width
        extra = forced_type.width - type(symtab).width
        mock_type = Struct.new(:width)
        c = ConcatenationExpressionAst.new(
          input, interval, [PruneHelpers.create_int_literal(0, forced_type: mock_type.new(extra))] + @children.map { |c| c.prune(symtab) }
        )
      end
    end
    c
  end
end

#to_hObject



5551
5552
5553
5554
5555
# File 'lib/idlc/ast.rb', line 5551

def to_h = {
  "kind" => "concat_expr",
  "exprs" => expressions.map(&:to_h),
  "source" => source_yaml
}

#to_idlObject



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

def to_idl = "{#{expressions.map { |exp| exp.to_idl }.join(',')}}"

#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

Parameters:

Returns:

  • (Type)

    The type of the node

Raises:



5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
# File 'lib/idlc/ast.rb', line 5497

def type(symtab)
  all_known_values = T.let(true, T::Boolean)
  width_known = T.let(true, T::Boolean)

  is_const = T.let(true, T::Boolean)
  total_width = expressions.reduce(0) do |sum, exp|
    e_type = exp.type(symtab)
    if e_type.width == :unknown
      width_known = false
    elsif width_known
      sum = sum + e_type.width
    end
    all_known_values &= e_type.known?
    sum
  end

  qualifiers = is_const ? [:const] : []

  if all_known_values
    qualifiers << :known
    if width_known
      Type.new(:bits, width: total_width, qualifiers:)
    else
      Type.new(:bits, width: :unknown, qualifiers:)
    end
  else
    if width_known
      Type.new(:bits, width: total_width, qualifiers:)
    else
      Type.new(:bits, width: :unknown, qualifiers:)
    end
  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:



5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
# File 'lib/idlc/ast.rb', line 5484

def type_check(symtab, strict:)
  type_error "Must concatenate at least two objects" if expressions.size < 2

  expressions.each do |exp|
    exp.type_check(symtab, strict:)
    e_type = exp.type(symtab)
    type_error "Concatenation only supports Bits<> types" unless e_type.kind == :bits

    internal_error "Negative width for element #{exp.text_value}" if (e_type.width != :unknown) && (e_type.width <= 0)
  end
end

#value(symtab) ⇒ Object

Return the compile-time-known value of the node



5532
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
# File 'lib/idlc/ast.rb', line 5532

def value(symtab)
  result = T.let(UnknownLiteral.new(0, 0), T.any(Integer, UnknownLiteral))
  total_width = 0
  expressions.reverse_each do |exp|
    result |= (exp.value(symtab) << total_width)
    total_width += exp.type(symtab).width
  end
  if result.is_a?(UnknownLiteral)
    result.unknown_mask.zero? ? result.known_value : result
  else
    result
  end
end