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



5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
# File 'lib/idlc/ast.rb', line 5543

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)


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

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

#expressionsObject



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

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



5536
5537
5538
5539
5540
# File 'lib/idlc/ast.rb', line 5536

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

#to_idlObject



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

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:



5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
# File 'lib/idlc/ast.rb', line 5482

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:



5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
# File 'lib/idlc/ast.rb', line 5469

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



5517
5518
5519
5520
5521
5522
5523
5524
5525
5526
5527
5528
5529
# File 'lib/idlc/ast.rb', line 5517

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