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.
7494
7495
7496
7497
7498
|
# File 'lib/idlc/ast.rb', line 7494
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
7807
7808
7809
7810
7811
7812
7813
7814
7815
7816
|
# File 'lib/idlc/ast.rb', line 7807
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
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
|
# File 'lib/idlc/ast.rb', line 7795
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
7491
|
# File 'lib/idlc/ast.rb', line 7491
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
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
|
# File 'lib/idlc/ast.rb', line 7746
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
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
|
# File 'lib/idlc/ast.rb', line 7729
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
7500
|
# File 'lib/idlc/ast.rb', line 7500
def text_value = @text
|
#to_h ⇒ Object
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
|
# File 'lib/idlc/ast.rb', line 7784
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
7726
|
# File 'lib/idlc/ast.rb', line 7726
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
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
|
# File 'lib/idlc/ast.rb', line 7519
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
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
|
# File 'lib/idlc/ast.rb', line 7503
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).
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
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
|
# File 'lib/idlc/ast.rb', line 7645
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
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
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
|
# File 'lib/idlc/ast.rb', line 7598
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
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
|
# File 'lib/idlc/ast.rb', line 7559
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
|