Class: Idl::IntLiteralAst

Inherits:
AstNode
  • Object
show all
Includes:
Rvalue
Defined in:
lib/idl/ast.rb

Overview

represents an integer literal

Instance Method Summary collapse

Constructor Details

#initialize(input, interval) ⇒ IntLiteralAst

Returns a new instance of IntLiteralAst.



4321
4322
4323
# File 'lib/idl/ast.rb', line 4321

def initialize(input, interval)
  super(input, interval, EMPTY_ARRAY)
end

Instance Method Details

#freeze_tree(global_symtab) ⇒ Object



4325
4326
4327
4328
4329
4330
4331
4332
# File 'lib/idl/ast.rb', line 4325

def freeze_tree(global_symtab)
  return if frozen?

  # initialize the cached objects
  type(global_symtab)
  value(global_symtab)
  freeze
end

#to_idlString

Return valid IDL representation of the node (and its subtree)

Returns:

  • (String)

    IDL code for the node



4518
# File 'lib/idl/ast.rb', line 4518

def to_idl = text_value

#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:



4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
# File 'lib/idl/ast.rb', line 4351

def type(symtab)
  return @type unless @type.nil?

  case text_value.delete("_")
  when /^((XLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
    # verilog-style literal
    signed = ::Regexp.last_match(4)
    width = width(symtab)

    unless width == :unknown
      type_error("integer width must be positive (is #{width})") unless width.is_a?(Integer) && width.positive?
    end

    qualifiers = signed == "s" ? [:signed, :const] : [:const]
    @type = Type.new(:bits, width:, qualifiers:)
  when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
    # C++-style literal
    signed = ::Regexp.last_match(3)

    qualifiers = signed == "s" ? [:signed, :const] : [:const]
    @type = Type.new(:bits, width: width(symtab), qualifiers:)
  when /^([0-9]*)(s?)$/
    # basic decimal
    signed = ::Regexp.last_match(2)

    qualifiers = signed == "s" ? [:signed, :const] : [:const]
    @type = Type.new(:bits, width: width(symtab), qualifiers:)
  else
    internal_error "Unhandled int value"
  end
end

#type_check(symtab) ⇒ 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:



4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
# File 'lib/idl/ast.rb', line 4335

def type_check(symtab)
  if text_value.delete("_") =~ /^((XLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
    # verilog-style literal
    width = ::Regexp.last_match(1)
    value_text = ::Regexp.last_match(6)

    if width.nil? || width == "XLEN"
      width = symtab.mxlen.nil? ? 32 : symtab.mxlen # 32 is the min width, which is what we care about here
    end

    # ensure we actually have enough bits to represent the value
    type_error("#{value_text} cannot be represented in #{width} bits") if unsigned_value.bit_length > width.to_i
  end
end

#unsigned_valueInteger

Returns the unsigned value of this literal (i.e., treating it as unsigned even if the signed specifier is present).

Returns:

  • (Integer)

    the unsigned value of this literal (i.e., treating it as unsigned even if the signed specifier is present)



4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
# File 'lib/idl/ast.rb', line 4465

def unsigned_value
  return @unsigned_value unless @unsigned_value.nil?

  @unsigned_value =
    case text_value.delete("_")
    when /^((XLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
      # verilog-style literal
      radix_id = ::Regexp.last_match(5)
      value = ::Regexp.last_match(6)

      radix_id = "d" if radix_id.empty?

      case radix_id
      when "b"
        value.to_i(2)
      when "o"
        value.to_i(8)
      when "d"
        value.to_i(10)
      when "h"
        value.to_i(16)
      end
    when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
      # C++-style literal
      radix_id = ::Regexp.last_match(1)
      value = ::Regexp.last_match(2)

      radix_id = "o" if radix_id.empty?

      # @unsigned_value =
        case radix_id
        when "b"
          value.to_i(2)
        when "o"
          value.to_i(8)
        when "d"
          value.to_i(10)
        when "x"
          value.to_i(16)
        end

    when /^([0-9]*)(s?)$/
      # basic decimal
      value = ::Regexp.last_match(1)

      # @unsigned_value = value.to_i(10)
      value.to_i(10)
    else
      internal_error "Unhandled int value '#{text_value}'"
    end
end

#value(symtab) ⇒ Object

Return the compile-time-known value of the node



4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
# File 'lib/idl/ast.rb', line 4418

def value(symtab)
  return @value unless @value.nil?

  if text_value.delete("_") =~ /^((XLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
    # verilog-style literal
    signed = ::Regexp.last_match(4)
    width = width(symtab)

    v =
      if width == :unknown
        if !signed.empty?
          if unsigned_value > 0x7fff_ffff
            value_error("Don't know if value will be negative")
          else
            if unsigned_value > 0xffff_ffff
              value_error("Don't know if value will fit in literal")
            end
            unsigned_value
          end
        else
          if unsigned_value > 0xffff_ffff
            value_error("Don't know if value will fit in literal")
          end
          unsigned_value
        end
      else
        if unsigned_value.bit_length > width
          value_error("Value does not fit in literal")
        end
        if !signed.empty? && ((unsigned_value >> (width - 1)) == 1)
          if unsigned_value.bit_length > (width - 1)
            value_error("Value does not fit in literal")
          end
          -(2**width.to_i - unsigned_value)
        else
          unsigned_value
        end
      end

    @value = v
  else
    @value = unsigned_value
  end
end

#values(symtab) ⇒ Array<Integer>, ... Originally defined in module Rvalue

Return a complete list of possible compile-time-known values of the node, or raise a ValueError if the full list cannot be determined

For most AstNodes, this will just be a single-entry array

Parameters:

  • symtab (SymbolTable)

    The context for the evaluation

Returns:

  • (Array<Integer>)

    The complete list of compile-time-known values, when they are integral

  • (Array<Boolean>)

    The complete list of compile-time-known values, when they are booleans

  • (AstNode::ValueError)

    if the list of values is not knowable at compile time

#width(symtab) ⇒ Object



4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
# File 'lib/idl/ast.rb', line 4383

def width(symtab)
  return @width unless @width.nil?

  text_value_no_underscores = text_value.delete("_")

  case text_value_no_underscores
  when /^((XLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
    # verilog-style literal
    width = ::Regexp.last_match(1)
    if width.nil? || width == "XLEN"
      width = symtab.mxlen.nil? ? :unknown : symtab.mxlen
    else
      width = width.to_i
    end
    @width = width
  when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
    signed = ::Regexp.last_match(3)

    width = signed == "s" ? value(symtab).bit_length + 1 : value(symtab).bit_length
    width = 1 if width.zero? # happens when the literal is '0'

    @width = width
  when /^([0-9]*)(s?)$/
    signed = ::Regexp.last_match(3)

    width = signed == "s" ? value(symtab).bit_length + 1 : value(symtab).bit_length
    width = 1 if width.zero? # happens when the literal is '0'

    @width = width
  else
    internal_error "No match on int literal"
  end
end