Class: Idl::IntLiteralAst
- Inherits:
-
AstNode
show all
- Includes:
- Rvalue
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/gen_option_adoc.rb
Overview
represents an integer literal
Defined Under Namespace
Classes: Memo
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, #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, #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, text) ⇒ IntLiteralAst
Returns a new instance of IntLiteralAst.
7479
7480
7481
7482
7483
|
# File 'lib/idlc/ast.rb', line 7479
def initialize(input, interval, text)
@text = text
super(input, interval, EMPTY_ARRAY)
@memo = Memo.new
end
|
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
|
# File 'lib/idlc/ast.rb', line 7792
def self.from_h(yaml, source_mapper)
raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "bits_literal"
input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
interval = interval_from_source_yaml(yaml.fetch("source"))
text = "#{yaml.fetch("width")}'#{yaml.fetch("signed") ? "s" : ""}#{radix_to_verilog(yaml.fetch("radix"))}#{yaml.fetch("value").to_s(yaml.fetch("radix"))}"
IntLiteralAst.new(
input, interval, text
)
end
|
.radix_to_verilog(r) ⇒ Object
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
|
# File 'lib/idlc/ast.rb', line 7780
def self.radix_to_verilog(r)
case r
when 2 then "b"
when 8 then "o"
when 10 then "d"
when 16 then "h"
else
raise "bad radix: #{r}"
end
end
|
Instance Method Details
#const_eval?(symtab) ⇒ Boolean
7476
|
# File 'lib/idlc/ast.rb', line 7476
def const_eval?(symtab) = true
|
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
147
148
149
150
|
# File 'lib/idlc/passes/gen_adoc.rb', line 147
def gen_adoc(indent = 0, indent_spaces: 2)
raise "?" if text_value.empty?
"#{' ' * indent}#{text_value}"
end
|
#gen_option_adoc ⇒ Object
103
104
105
106
107
108
109
110
111
|
# File 'lib/idlc/passes/gen_option_adoc.rb', line 103
def gen_option_adoc
if value(nil) == 1 << 65
"UNDEFINED_LEGAL"
elsif value(nil) == 1 << 66
"UNDEFINED_LEGAL_DETERMINISTIC"
else
text_value
end
end
|
#prune(symtab, forced_type: nil) ⇒ Object
694
695
696
697
698
699
700
701
702
|
# File 'lib/idlc/passes/prune.rb', line 694
def prune(symtab, forced_type: nil)
if forced_type
raise "pruning error: attempt to force bitwidth when width is unknown" if forced_type.width.nil? || forced_type.width == :unknown
s = "#{forced_type.width}'d#{value(symtab)}"
IntLiteralAst.new(s, 0...s.size, s)
else
dup
end
end
|
#radix ⇒ Object
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
|
# File 'lib/idlc/ast.rb', line 7731
def radix
case text_value.delete("_")
when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
r = T.must(::Regexp.last_match(5))
if r.empty?
10
elsif r == "b"
2
elsif r == "o"
8
elsif r == "d"
10
elsif r == "h"
16
else
raise "unhandled literal"
end
when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
r = T.must(::Regexp.last_match(1))
if r.empty?
10
elsif r == "b"
2
elsif r == "d"
10
elsif r == "x"
16
else
raise "unhandled literal: #{r}"
end
when /^([0-9]*)(s?)$/
10
else
raise "unhandled literal"
end
end
|
#signed? ⇒ Boolean
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
|
# File 'lib/idlc/ast.rb', line 7714
def signed?
case text_value.delete("_")
when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
signed = T.must(::Regexp.last_match(4))
!signed.empty?
when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
signed = T.must(::Regexp.last_match(3))
!signed.empty?
when /^([0-9]*)(s?)$/
signed = T.must(::Regexp.last_match(2))
!signed.empty?
else
raise "unhandled literal"
end
end
|
#text_value ⇒ Object
7485
|
# File 'lib/idlc/ast.rb', line 7485
def text_value = @text
|
#to_h ⇒ Object
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
|
# File 'lib/idlc/ast.rb', line 7769
def to_h
{
"kind" => "bits_literal",
"width" => (width(nil) == :unknown) ? "MXLEN" : width(nil).to_s,
"value" => unsigned_value,
"signed" => signed?,
"radix" => radix,
"source" => source_yaml
}
end
|
#to_idl ⇒ Object
7711
|
# File 'lib/idlc/ast.rb', line 7711
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
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
|
# File 'lib/idlc/ast.rb', line 7504
def type(symtab)
return @memo.type unless @memo.type.nil?
case text_value.delete("_")
when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
signed = ::Regexp.last_match(4)
value = ::Regexp.last_match(6)
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]
qualifiers << :known unless T.must(value).include?("x")
@memo.type =
if width == :unknown
Type.new(:bits, width:, max_width: 64, qualifiers:)
else
Type.new(:bits, width:, qualifiers:)
end
when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
signed = ::Regexp.last_match(3)
qualifiers = signed == "s" ? [:signed, :const, :known] : [:const, :known]
@memo.type = Type.new(:bits, width: width(symtab), qualifiers:)
when /^([0-9]*)(s?)$/
signed = ::Regexp.last_match(2)
qualifiers = signed == "s" ? [:signed, :const, :known] : [:const, :known]
@memo.type = Type.new(:bits, width: width(symtab), qualifiers:)
else
internal_error "Unhandled int value '#{text_value}'"
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
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
|
# File 'lib/idlc/ast.rb', line 7488
def type_check(symtab, strict:)
if text_value.delete("_") =~ /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
width = ::Regexp.last_match(1)
value_text = ::Regexp.last_match(6)
if width.nil? || width == "MXLEN"
width = symtab.mxlen.nil? ? 32 : symtab.mxlen end
type_error("#{value_text} cannot be represented in #{width} bits") if unsigned_value.bit_length > width.to_i
end
end
|
#unsigned_value ⇒ Integer
Returns the unsigned value of this literal (i.e., treating it as unsigned even if the signed specifier is present).
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
|
# File 'lib/idlc/ast.rb', line 7630
def unsigned_value
return @memo.unsigned_value unless @memo.unsigned_value.nil?
@memo.unsigned_value =
case text_value.delete("_")
when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
radix_id = T.must(::Regexp.last_match(5))
value = T.must(::Regexp.last_match(6))
radix_id = "d" if radix_id.empty?
if value.index("x").nil? && value.index("X").nil?
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
else
known_value =
case radix_id
when "b"
value.gsub(/[xX]/, "0").to_i(2)
when "o"
value.gsub(/[xX]/, "0").to_i(8)
when "d"
raise "impossible"
when "h"
value.gsub(/[xX]/, "0").to_i(16)
end
unknown_mask =
case radix_id
when "b"
value.gsub("1", "0").gsub(/[xX]/, "1").to_i(2)
when "o"
value.gsub(/[0-7]/, "0").gsub(/[xX]/, "7").to_i(8)
when "d"
raise "impossible"
when "h"
value.gsub(/[0-9a-fA-F]/, "0").gsub(/[xX]/, "f").to_i(16)
end
UnknownLiteral.new(known_value, unknown_mask)
end
when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
radix_id = T.must(::Regexp.last_match(1))
value = T.must(::Regexp.last_match(2))
radix_id = "o" 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 "x"
value.to_i(16)
end
when /^([0-9]*)(s?)$/
value = T.must(::Regexp.last_match(1))
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
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
|
# File 'lib/idlc/ast.rb', line 7583
def value(symtab)
return @memo.value unless @memo.value.nil?
if text_value.delete("_") =~ /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
signed = T.must(::Regexp.last_match(4))
width = width(symtab)
v =
if width == :unknown || width == "MXLEN"
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
@memo.value = v
else
@memo.value = unsigned_value
end
end
|
#width(symtab) ⇒ Object
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
|
# File 'lib/idlc/ast.rb', line 7544
def width(symtab)
return @memo.width unless @memo.width.nil?
text_value_no_underscores = text_value.delete("_")
case text_value_no_underscores
when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
width = ::Regexp.last_match(1)
if width.nil? || width == "MXLEN"
if symtab.nil?
width = :unknown
else
width = symtab.mxlen.nil? ? :unknown : symtab.mxlen
end
else
width = width.to_i
end
@memo.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?
@memo.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?
@memo.width = width
else
internal_error "No match on int literal"
end
end
|