idlc 0.1.1 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/idlc/ast.rb CHANGED
@@ -65,11 +65,15 @@ module Idl
65
65
 
66
66
  # @return [String] Source input file
67
67
  sig { returns(T.nilable(Pathname)) }
68
- attr_reader :input_file
68
+ def input_file
69
+ @input_file || @parent&.input_file
70
+ end
69
71
 
70
72
  # @return [Integer] Starting line in the source input file (i.e., position 0 of {#input} in the file)
71
73
  sig { returns(Integer) }
72
- attr_reader :starting_line
74
+ def starting_line
75
+ @starting_line || @parent&.starting_line || 0
76
+ end
73
77
 
74
78
  # @return [String] Source string
75
79
  sig { returns(T.nilable(String)) }
@@ -212,6 +216,14 @@ module Idl
212
216
  sig { abstract.params(symtab: SymbolTable).returns(T::Boolean) }
213
217
  def const_eval?(symtab); end
214
218
 
219
+ # @return [Boolean] whether this node includes the Executable interface
220
+ sig { overridable.returns(T::Boolean).checked(:never) }
221
+ def executable? = false
222
+
223
+ # @return [Boolean] whether this node includes the Declaration interface
224
+ sig { overridable.returns(T::Boolean).checked(:never) }
225
+ def declaration? = false
226
+
215
227
  # @param input [String] The source being compiled
216
228
  # @param interval [Range] The range in the source corresponding to this AstNode
217
229
  # @param children [Array<AstNode>] Children of this node
@@ -247,7 +259,7 @@ module Idl
247
259
  # @param [Integer] starting_line The starting line number in the input file.
248
260
  # @param [Integer] starting_offset The byte offset in the file where the IDL content starts.
249
261
  # @param [Array<Integer>, nil] line_file_offsets Per-IDL-line file byte offsets (nil = use starting_offset).
250
- sig { params(filename: T.any(Pathname, String), starting_line: Integer, starting_offset: Integer, line_file_offsets: T.nilable(T::Array[Integer])).void }
262
+ sig { params(filename: T.any(Pathname, String), starting_line: Integer, starting_offset: Integer, line_file_offsets: T.nilable(T::Array[Integer])).void.checked(:never) }
251
263
  def set_input_file_unless_already_set(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil)
252
264
  return unless @input_file.nil?
253
265
 
@@ -255,10 +267,6 @@ module Idl
255
267
  @starting_line = starting_line
256
268
  @starting_offset = starting_offset
257
269
  @line_file_offsets = line_file_offsets
258
- children.each do |child|
259
- child.set_input_file_unless_already_set(filename, starting_line, starting_offset, line_file_offsets)
260
- end
261
- raise "?" if @starting_line.nil?
262
270
  end
263
271
 
264
272
  # remember where the code comes from
@@ -267,22 +275,18 @@ module Idl
267
275
  # @param starting_line [Integer] Starting line in the file
268
276
  # @param starting_offset [Integer] Byte offset in the file where the IDL content starts
269
277
  # @param line_file_offsets [Array<Integer>, nil] Per-IDL-line file byte offsets (nil = use starting_offset).
270
- sig { params(filename: T.any(Pathname, String), starting_line: Integer, starting_offset: Integer, line_file_offsets: T.nilable(T::Array[Integer])).void }
278
+ sig { params(filename: T.any(Pathname, String), starting_line: Integer, starting_offset: Integer, line_file_offsets: T.nilable(T::Array[Integer])).void.checked(:never) }
271
279
  def set_input_file(filename, starting_line = 0, starting_offset = 0, line_file_offsets = nil)
272
280
  @input_file = Pathname.new(filename)
273
281
  @starting_line = starting_line
274
282
  @starting_offset = starting_offset
275
283
  @line_file_offsets = line_file_offsets
276
- children.each do |child|
277
- child.set_input_file(filename, starting_line, starting_offset, line_file_offsets)
278
- end
279
- raise "?" if @starting_line.nil?
280
284
  end
281
285
 
282
286
  # @return [Integer] the current line number
283
287
  sig { returns(Integer) }
284
288
  def lineno
285
- T.must(T.must(input)[0..T.must(interval).first]).count("\n") + 1 + (@starting_line.nil? ? 0 : @starting_line)
289
+ T.must(T.must(input)[0..T.must(interval).first]).count("\n") + 1 + starting_line
286
290
  end
287
291
 
288
292
  # @return [AstNode] the first ancestor that is_a?(+klass+)
@@ -378,7 +382,7 @@ module Idl
378
382
  starting_lineno = T.must(T.must(input)[0..lines_interval.min]).count("\n")
379
383
  lines = lines.lines.map do |line|
380
384
  starting_lineno += 1
381
- "#{@starting_line + starting_lineno - 1}: #{line}"
385
+ "#{starting_line + starting_lineno - 1}: #{line}"
382
386
  end.join("")
383
387
 
384
388
  msg = <<~WHAT
@@ -415,6 +419,57 @@ module Idl
415
419
  attr_accessor :value_error_reason, :value_error_ast
416
420
  end
417
421
 
422
+ # Extract the base variable name from a potentially nested access chain
423
+ # @param node [RvalueAst] The node to extract from
424
+ # @return [String, nil] The base variable name, or nil if not extractable
425
+ sig { params(node: RvalueAst).returns(T.nilable(String)) }
426
+ def self.extract_base_var_name(node)
427
+ case node
428
+ when IdAst
429
+ node.name
430
+ when AryElementAccessAst, AryRangeAccessAst
431
+ extract_base_var_name(node.var)
432
+ else
433
+ nil
434
+ end
435
+ end
436
+
437
+ # Perform write-back for nested array access assignments
438
+ # Handles arbitrary nesting depth: v[a][b][c] = val recursively writes back through the chain
439
+ # @param target [RvalueAst] The target expression (possibly nested)
440
+ # @param new_value [Integer] The new value to write
441
+ # @param symtab [SymbolTable] The symbol table
442
+ # @return [void]
443
+ sig { params(target: RvalueAst, new_value: ValueRbType, symtab: SymbolTable).void }
444
+ def self.write_back_nested(target, new_value, symtab)
445
+ case target
446
+ when IdAst
447
+ # Base case: simple variable
448
+ existing_var = symtab.get(target.name)
449
+ raise InternalError, "write_back_nested: '#{target.name}' not found in symbol table" if existing_var.nil?
450
+ existing_var.value = new_value
451
+ when AryElementAccessAst
452
+ # Recursive case: v[idx] = val
453
+ # Read parent, modify element, write back parent
454
+ parent_value = target.var.value(symtab)
455
+ idx_val = target.index.value(symtab)
456
+ parent_value[idx_val] = new_value
457
+ # Recursively write back the parent (which may itself be nested)
458
+ write_back_nested(target.var, parent_value, symtab)
459
+ when AryRangeAccessAst
460
+ # Recursive case: v[msb:lsb] = new_value
461
+ # Read parent, splice new_value into [msb:lsb], write parent back
462
+ parent_value = T.cast(target.var.value(symtab), Integer)
463
+ msb_val = T.cast(target.msb.value(symtab), Integer)
464
+ lsb_val = T.cast(target.lsb.value(symtab), Integer)
465
+ mask = ((1 << (msb_val - lsb_val + 1)) - 1) << lsb_val
466
+ updated_parent = (parent_value & ~mask) | ((T.cast(new_value, Integer) << lsb_val) & mask)
467
+ write_back_nested(target.var, updated_parent, symtab)
468
+ else
469
+ raise InternalError, "Unknown target type for write-back: #{target.class.name}"
470
+ end
471
+ end
472
+
418
473
  # raise a value error, indicating that the value is not known at compile time
419
474
  #
420
475
  # @param reason [String] Error message
@@ -461,9 +516,6 @@ module Idl
461
516
  # This is also an opportunity to pre-calculate anything that only needs global symbols
462
517
  #
463
518
  # @param global_symtab [SymbolTable] Symbol table with global scope populated
464
-
465
-
466
- # @!macro freeze_tree
467
519
  sig { params(global_symtab: SymbolTable).returns(AstNode) }
468
520
  def freeze_tree(global_symtab)
469
521
  return self if frozen?
@@ -508,9 +560,6 @@ module Idl
508
560
  sig { abstract.returns(String) }
509
561
  def to_idl; end
510
562
 
511
- sig { overridable.returns(String) }
512
- def to_idl_verbose = to_idl
513
-
514
563
  # return yaml to indicate where the node comes from
515
564
  # the retrun value will be:
516
565
  # file: <path to input file (or nil if input was given as a string)>
@@ -518,11 +567,11 @@ module Idl
518
567
  # end: <0-indexed position of the ending character in the input>
519
568
  sig { returns(T::Hash[String, T.untyped]) }
520
569
  def source_yaml
521
- base_offset = @starting_offset || 0
570
+ base_offset = source_starting_offset
522
571
  interval_begin = T.must(interval).begin
523
572
  interval_end = T.must(interval).size == 0 ? T.must(interval).begin + 1 : T.must(interval).end
524
573
 
525
- lfo = @line_file_offsets
574
+ lfo = source_line_file_offsets
526
575
  if lfo
527
576
  # Map an IDL-string position to a file byte offset using the per-line table.
528
577
  # Each entry lfo[i] is the file offset of the first character of IDL line i.
@@ -545,12 +594,23 @@ module Idl
545
594
  end
546
595
 
547
596
  {
548
- "file" => @input_file.to_s,
597
+ "file" => T.must(input_file).to_s,
549
598
  "begin" => file_begin,
550
599
  "end" => file_end
551
600
  }
552
601
  end
553
602
 
603
+ sig { returns(Integer) }
604
+ def source_starting_offset
605
+ @starting_offset || @parent&.source_starting_offset || 0
606
+ end
607
+
608
+ sig { returns(T.nilable(T::Array[Integer])) }
609
+ def source_line_file_offsets
610
+ return @line_file_offsets unless @line_file_offsets.nil?
611
+ @parent&.source_line_file_offsets
612
+ end
613
+
554
614
  private
555
615
 
556
616
  # Given an IDL-string position +pos+ and the per-line file-offset table +lfo+,
@@ -679,7 +739,10 @@ module Idl
679
739
  module Executable
680
740
  extend T::Sig
681
741
  extend T::Helpers
682
- interface!
742
+ abstract!
743
+
744
+ sig { returns(T::Boolean).checked(:never) }
745
+ def executable? = true
683
746
 
684
747
  # @!macro [new] execute
685
748
  # "execute" the statement by updating the variables in the symbol table
@@ -866,7 +929,10 @@ module Idl
866
929
  module Declaration
867
930
  extend T::Sig
868
931
  extend T::Helpers
869
- interface!
932
+ abstract!
933
+
934
+ sig { returns(T::Boolean).checked(:never) }
935
+ def declaration? = true
870
936
 
871
937
  # @!macro [new] add_symbol
872
938
  # Add symbol(s) at the outermost scope of the symbol table
@@ -1345,9 +1411,13 @@ module Idl
1345
1411
 
1346
1412
  enums.each { |g| g.add_symbol(symtab); }
1347
1413
  bitfields.each { |g| g.add_symbol(symtab) }
1414
+ # Functions must be registered before globals so that global variable
1415
+ # initializers can call functions (e.g. FLEN = implemented?(...) ? 64 : 32).
1416
+ # FunctionDefAst#add_symbol only stores the FunctionType; it does not
1417
+ # evaluate the body, so adding functions before globals is safe.
1418
+ functions.each { |g| g.add_symbol(symtab) }
1348
1419
  globals.each { |g| g.add_symbol(symtab) }
1349
1420
  structs.each { |g| g.add_symbol(symtab) }
1350
- functions.each { |g| g.add_symbol(symtab) }
1351
1421
  end
1352
1422
 
1353
1423
  # replaces an include statement with the ast in that file, making
@@ -1424,7 +1494,9 @@ module Idl
1424
1494
  end
1425
1495
  end
1426
1496
 
1427
- IsaAst.new(input, interval, kids)
1497
+ node = IsaAst.new(input, interval, kids)
1498
+ node.set_input_file(yaml.fetch("source").fetch("file"))
1499
+ node
1428
1500
  end
1429
1501
  end
1430
1502
 
@@ -1499,12 +1571,6 @@ module Idl
1499
1571
  end
1500
1572
  end
1501
1573
 
1502
- class ArraySizeSyntaxNode < SyntaxNode
1503
- def to_ast
1504
- ArraySizeAst.new(input, interval, send(:expression).to_ast)
1505
- end
1506
- end
1507
-
1508
1574
  class ArraySizeAst < AstNode
1509
1575
  include Rvalue
1510
1576
 
@@ -1566,25 +1632,21 @@ module Idl
1566
1632
  end
1567
1633
 
1568
1634
 
1569
- class EnumSizeSyntaxNode < SyntaxNode
1570
- def to_ast
1571
- EnumSizeAst.new(input, interval, send(:type_name).to_ast)
1572
- end
1573
- end
1574
-
1575
1635
  # represents the builtin that returns the nymber of elements in an enum class
1576
1636
  #
1577
1637
  # $enum_size(XRegWidth) #=> 2
1578
1638
  class EnumSizeAst < AstNode
1579
1639
  include Rvalue
1580
1640
 
1581
- def enum_class = children[0]
1641
+ def enum_class = children.fetch(0)
1582
1642
 
1583
1643
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
1584
1644
  def const_eval?(symtab) = true
1585
1645
 
1646
+ sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: T.any(IdAst, UserTypeNameAst)).void }
1586
1647
  def initialize(input, interval, enum_class_name)
1587
- super(input, interval, [enum_class_name])
1648
+ user_type_name = enum_class_name.is_a?(UserTypeNameAst) ? enum_class_name : UserTypeNameAst.new(enum_class_name.input, enum_class_name.interval, enum_class_name.name)
1649
+ super(input, interval, [user_type_name])
1588
1650
  end
1589
1651
 
1590
1652
  def type_check(symtab, strict:)
@@ -1621,17 +1683,11 @@ module Idl
1621
1683
  interval = interval_from_source_yaml(yaml.fetch("source"))
1622
1684
  EnumSizeAst.new(
1623
1685
  input, interval,
1624
- T.cast(AstNode.from_h(yaml.fetch("enum_class_name"), source_mapper), T.all(Rvalue, AstNode))
1686
+ T.cast(AstNode.from_h(yaml.fetch("enum_class_name"), source_mapper), UserTypeNameAst)
1625
1687
  )
1626
1688
  end
1627
1689
  end
1628
1690
 
1629
- class EnumElementSizeSyntaxNode < SyntaxNode
1630
- def to_ast
1631
- EnumElementSizeAst.new(input, interval, send(:type_name).to_ast)
1632
- end
1633
- end
1634
-
1635
1691
  # represents the builtin that returns the bitwidth of an element in an enum class
1636
1692
  #
1637
1693
  # $enum_element_size(PrivilegeMode) #=> 3
@@ -1643,9 +1699,10 @@ module Idl
1643
1699
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
1644
1700
  def const_eval?(symtab) = true
1645
1701
 
1646
- sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: UserTypeNameAst).void }
1702
+ sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: T.any(IdAst, UserTypeNameAst)).void }
1647
1703
  def initialize(input, interval, enum_class_name)
1648
- super(input, interval, [enum_class_name])
1704
+ user_type_name = enum_class_name.is_a?(UserTypeNameAst) ? enum_class_name : UserTypeNameAst.new(enum_class_name.input, enum_class_name.interval, enum_class_name.name)
1705
+ super(input, interval, [user_type_name])
1649
1706
  end
1650
1707
 
1651
1708
  def type_check(symtab, strict:)
@@ -1683,12 +1740,6 @@ module Idl
1683
1740
  end
1684
1741
  end
1685
1742
 
1686
- class EnumCastSyntaxNode < SyntaxNode
1687
- def to_ast
1688
- EnumCastAst.new(input, interval, send(:type_name).to_ast, send(:expression).to_ast)
1689
- end
1690
- end
1691
-
1692
1743
  class EnumCastAst < AstNode
1693
1744
  include Rvalue
1694
1745
 
@@ -1696,22 +1747,23 @@ module Idl
1696
1747
  def const_eval?(symtab) = true
1697
1748
 
1698
1749
  # @return [UserTypeAst] Enum name
1699
- def enum_name = @children[0]
1750
+ def enum_name = @children.fetch(0)
1700
1751
 
1701
1752
  # @return [Rvalue] Value expression
1702
- def expression = @children[1]
1753
+ def expression = @children.fetch(1)
1703
1754
 
1704
1755
  sig {
1705
1756
  params(
1706
1757
  input: T.nilable(String),
1707
1758
  interval: T.nilable(T::Range[Integer]),
1708
- type_name: UserTypeNameAst,
1759
+ type_name: T.any(IdAst, UserTypeNameAst),
1709
1760
  expression: RvalueAst
1710
1761
  )
1711
1762
  .void
1712
1763
  }
1713
1764
  def initialize(input, interval, type_name, expression)
1714
- super(input, interval, [type_name, expression])
1765
+ user_type_name = type_name.is_a?(UserTypeNameAst) ? type_name : UserTypeNameAst.new(type_name.input, type_name.interval, type_name.name)
1766
+ super(input, interval, [user_type_name, expression])
1715
1767
  end
1716
1768
 
1717
1769
  def type_check(symtab, strict:)
@@ -1764,26 +1816,21 @@ module Idl
1764
1816
  end
1765
1817
  end
1766
1818
 
1767
- class EnumArrayCastSyntaxNode < SyntaxNode
1768
- def to_ast
1769
- EnumArrayCastAst.new(input, interval, send(:type_name).to_ast)
1770
- end
1771
- end
1772
-
1773
1819
  # represents the builtin that returns an array with all elements of an Enum type
1774
1820
  #
1775
1821
  # $enum_to_a(PrivilegeMode) #=> [3, 1, 1, 0, 5, 4]
1776
1822
  class EnumArrayCastAst < AstNode
1777
1823
  include Rvalue
1778
1824
 
1779
- def enum_class = children[0]
1825
+ def enum_class = children.fetch(0)
1780
1826
 
1781
1827
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
1782
1828
  def const_eval?(symtab) = true
1783
1829
 
1784
- sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: UserTypeNameAst).void }
1830
+ sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: T.any(IdAst, UserTypeNameAst)).void }
1785
1831
  def initialize(input, interval, enum_class_name)
1786
- super(input, interval, [enum_class_name])
1832
+ user_type_name = enum_class_name.is_a?(UserTypeNameAst) ? enum_class_name : UserTypeNameAst.new(enum_class_name.input, enum_class_name.interval, enum_class_name.name)
1833
+ super(input, interval, [user_type_name])
1787
1834
  end
1788
1835
 
1789
1836
  def type_check(symtab, strict:)
@@ -2184,49 +2231,50 @@ module Idl
2184
2231
  class BitfieldDefinitionAst < AstNode
2185
2232
  include Declaration
2186
2233
 
2234
+ class Memo < T::Struct
2235
+ prop :type, T.nilable(Type)
2236
+ prop :element_names, T.nilable(T::Array[String])
2237
+ prop :element_ranges, T.nilable(T::Hash[SymbolTable, T::Array[T::Range[Integer]]]), default: {}
2238
+ end
2239
+
2187
2240
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
2188
2241
  def const_eval?(symtab) = true
2189
2242
 
2243
+ sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), name: T.any(BuiltinTypeNameAst, UserTypeNameAst), size: IntLiteralAst, fields: T::Array[BitfieldFieldDefinitionAst]).void }
2190
2244
  def initialize(input, interval, name, size, fields)
2191
2245
  super(input, interval, [name, size] + fields)
2192
2246
 
2193
2247
  @name = name
2194
2248
  @size = size
2195
2249
  @fields = fields
2250
+ @memo = Memo.new
2196
2251
  end
2197
2252
 
2198
- # @!macro freeze_tree
2199
- def freeze_tree(global_symtab)
2200
- return if frozen?
2201
-
2202
- type(global_symtab)
2203
-
2204
- @children.each { |child| child.freeze_tree(global_symtab) }
2205
-
2206
- freeze
2207
- end
2208
-
2209
- # @return [Integer] The number of bits in the Bitfield
2253
+ # @return The number of bits in the Bitfield
2254
+ sig { params(symtab: SymbolTable).returns(Integer) }
2210
2255
  def size(symtab)
2211
2256
  @size.value(symtab)
2212
2257
  end
2213
2258
 
2214
- # @return [Array<String>] Array of all element names, in the same order as those from {#element_ranges}
2259
+ # @return Array of all element names, in the same order as those from {#element_ranges}
2260
+ sig { returns(T::Array[String]) }
2215
2261
  def element_names
2216
- return @element_names unless @element_names.nil?
2262
+ return @memo.element_names unless @memo.element_names.nil?
2217
2263
 
2218
- @element_names = @fields.map(&:name)
2264
+ @memo.element_names = @fields.map(&:name)
2219
2265
  end
2220
2266
 
2221
2267
  # @return [Array<Range>]
2222
2268
  # Array of all element ranges, in the same order as those from {#element_names}.
2269
+ sig { params(symtab: SymbolTable).returns(T::Array[T::Range[Integer]]) }
2223
2270
  def element_ranges(symtab)
2224
- return @element_ranges unless @element_ranges.nil?
2271
+ return @memo.element_ranges[symtab] unless @memo.element_ranges[symtab].nil?
2225
2272
 
2226
- @element_ranges = @fields.map { |f| f.range(symtab) }
2273
+ @memo.element_ranges[symtab] = @fields.map { |f| f.range(symtab) }
2227
2274
  end
2228
2275
 
2229
2276
  # @!macro type_check
2277
+ sig { override.params(symtab: SymbolTable, strict: T::Boolean).void }
2230
2278
  def type_check(symtab, strict:)
2231
2279
  type_error "Cannot use reserved word '#{name}' as user-defined type name" if ReservedWords::RESERVED.include?(name)
2232
2280
 
@@ -2242,20 +2290,21 @@ module Idl
2242
2290
  end
2243
2291
 
2244
2292
  # @!macro add_symbol
2293
+ sig { override.params(symtab: SymbolTable).void }
2245
2294
  def add_symbol(symtab)
2246
2295
  internal_error "All Bitfields should be declared at global scope" unless symtab.levels == 1
2247
2296
 
2248
2297
  t = type(symtab)
2249
- internal_error "Type is nil" if t.nil?
2250
2298
 
2251
2299
  symtab.add!(name, t)
2252
2300
  end
2253
2301
 
2254
2302
  # @!macro type_no_args
2303
+ sig { params(symtab: SymbolTable).returns(Type) }
2255
2304
  def type(symtab)
2256
- return @type unless @type.nil?
2305
+ return @memo.type unless @memo.type.nil?
2257
2306
 
2258
- @type = BitfieldType.new(
2307
+ @memo.type = BitfieldType.new(
2259
2308
  name,
2260
2309
  @size.value(symtab),
2261
2310
  element_names,
@@ -2264,9 +2313,11 @@ module Idl
2264
2313
  end
2265
2314
 
2266
2315
  # @return [String] bitfield name
2316
+ sig { returns(String) }
2267
2317
  def name = @name.text_value
2268
2318
 
2269
2319
  # @!macro value_no_args
2320
+ sig { params(_symtab: SymbolTable).returns(ValueRbType) }
2270
2321
  def value(_symtab) = raise AstNode::InternalError, "Bitfield definitions have no value"
2271
2322
 
2272
2323
  # @!macro to_idl
@@ -2289,7 +2340,7 @@ module Idl
2289
2340
  "source" => source_yaml
2290
2341
  }
2291
2342
 
2292
- sig { params(yaml: T::Hash[String, T.untyped], source_mapper: T::Hash[String, String]).returns(AstNode) }
2343
+ sig { override.params(yaml: T::Hash[String, T.untyped], source_mapper: T::Hash[String, String]).returns(AstNode) }
2293
2344
  def self.from_h(yaml, source_mapper)
2294
2345
  raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "bitfield_decl"
2295
2346
 
@@ -2297,8 +2348,8 @@ module Idl
2297
2348
  interval = interval_from_source_yaml(yaml.fetch("source"))
2298
2349
  BitfieldDefinitionAst.new(
2299
2350
  input, interval,
2300
- AstNode.from_h(yaml.fetch("name"), source_mapper),
2301
- AstNode.from_h(yaml.fetch("size"), source_mapper),
2351
+ T.cast(AstNode.from_h(yaml.fetch("name"), source_mapper), T.any(BuiltinTypeNameAst, UserTypeNameAst)),
2352
+ T.cast(AstNode.from_h(yaml.fetch("size"), source_mapper), IntLiteralAst),
2302
2353
  yaml.fetch("fields").map { |f| AstNode.from_h(f, source_mapper) }
2303
2354
  )
2304
2355
  end
@@ -2481,7 +2532,12 @@ module Idl
2481
2532
 
2482
2533
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
2483
2534
  def const_eval?(symtab)
2484
- if var.name == "X"
2535
+ var_type = begin
2536
+ var.type(symtab)
2537
+ rescue AstNode::TypeError, AstNode::InternalError
2538
+ nil
2539
+ end
2540
+ if var_type.is_a?(Type) && var_type.kind == :array && var_type.sub_type.is_a?(RegFileElementType) && var_type.qualifiers.include?(:global)
2485
2541
  false
2486
2542
  else
2487
2543
  var.const_eval?(symtab) && index.const_eval?(symtab)
@@ -2546,7 +2602,12 @@ module Idl
2546
2602
  if var.type(symtab).integral?
2547
2603
  (var_val >> index.value(symtab)) & 1
2548
2604
  else
2549
- value_error "X registers are not compile-time-known" if var.text_value == "X"
2605
+ var_type = begin
2606
+ var.type(symtab)
2607
+ rescue AstNode::TypeError, AstNode::InternalError
2608
+ nil
2609
+ end
2610
+ value_error "Register file registers are not compile-time-known" if var_type.is_a?(Type) && var_type.kind == :array && var_type.sub_type.is_a?(RegFileElementType) && var_type.qualifiers.include?(:global)
2550
2611
 
2551
2612
  # internal_error "Not an array" unless ary.type.kind == :array
2552
2613
 
@@ -2591,7 +2652,12 @@ module Idl
2591
2652
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
2592
2653
  def const_eval?(symtab)
2593
2654
  v = var
2594
- if v.is_a?(IdAst) && v.name == "X"
2655
+ var_type = begin
2656
+ v.type(symtab)
2657
+ rescue AstNode::TypeError, AstNode::InternalError
2658
+ nil
2659
+ end
2660
+ if var_type.is_a?(Type) && var_type.kind == :array && var_type.sub_type.is_a?(RegFileElementType) && var_type.qualifiers.include?(:global)
2595
2661
  false
2596
2662
  else
2597
2663
  v.const_eval?(symtab) && msb.const_eval?(symtab).const_eval? && lsb.const_eval?(symtab)
@@ -2855,12 +2921,6 @@ module Idl
2855
2921
  end
2856
2922
  end
2857
2923
 
2858
- class AryElementAssignmentSyntaxNode < SyntaxNode
2859
- def to_ast
2860
- AryElementAssignmentAst.new(input, interval, send(:var).to_ast, send(:idx).to_ast, send(:rval).to_ast)
2861
- end
2862
- end
2863
-
2864
2924
  # represents an array element assignment
2865
2925
  #
2866
2926
  # for example:
@@ -2875,8 +2935,10 @@ module Idl
2875
2935
  if idx.const_eval?(symtab) && rhs.const_eval?(symtab)
2876
2936
  true
2877
2937
  else
2878
- lhs_var = symtab.get(lhs.name)
2879
- type_error "array #{lhs.name} has not been declared" if lhs_var.nil?
2938
+ base_name = AstNode.extract_base_var_name(lhs)
2939
+ type_error "Cannot determine base variable for #{lhs.text_value}" if base_name.nil?
2940
+ lhs_var = symtab.get(base_name)
2941
+ type_error "array #{base_name} has not been declared" if lhs_var.nil?
2880
2942
 
2881
2943
  lhs_var.const_incompatible!
2882
2944
  false
@@ -2942,13 +3004,15 @@ module Idl
2942
3004
  value_error "right-hand side of array element assignment is unknown"
2943
3005
  end
2944
3006
  when :bits
2945
- var = symtab.get(lhs.text_value)
2946
3007
  value_result = value_try do
2947
- v = rhs.value(symtab)
2948
- var.value = (lhs.value(symtab) & ~0) | ((v & 1) << idx.value(symtab))
3008
+ new_element = (lhs.value(symtab) & ~0) | ((rhs.value(symtab) & 1) << idx.value(symtab))
3009
+ AstNode.write_back_nested(lhs, new_element, symtab)
2949
3010
  end
2950
3011
  value_else(value_result) do
2951
- var.value = nil
3012
+ base_name = T.must(AstNode.extract_base_var_name(lhs))
3013
+ v = symtab.get(base_name)
3014
+ internal_error "did not find array base '#{base_name}'" if v.nil?
3015
+ v.value = nil
2952
3016
  end
2953
3017
  else
2954
3018
  internal_error "unexpected type for array element assignment"
@@ -2985,7 +3049,27 @@ module Idl
2985
3049
 
2986
3050
  class AryRangeAssignmentSyntaxNode < SyntaxNode
2987
3051
  def to_ast
2988
- AryRangeAssignmentAst.new(input, interval, send(:var).to_ast, send(:msb).to_ast, send(:lsb).to_ast, send(:rval).to_ast)
3052
+ var = send(:var).to_ast
3053
+ brackets = send(:brackets).elements
3054
+
3055
+ # Build access chain for all but the last bracket
3056
+ brackets[0..-2].each do |bracket|
3057
+ var =
3058
+ if bracket.msb.empty?
3059
+ AryElementAccessAst.new(input, interval, var, bracket.lsb.to_ast)
3060
+ else
3061
+ AryRangeAccessAst.new(input, interval, var,
3062
+ bracket.msb.expression.to_ast, bracket.lsb.to_ast)
3063
+ end
3064
+ end
3065
+
3066
+ # Use accumulated `var` for the assignment target
3067
+ last_bracket = brackets[-1]
3068
+ if last_bracket.msb.empty?
3069
+ AryElementAssignmentAst.new(input, interval, var, last_bracket.lsb.to_ast, send(:rval).to_ast)
3070
+ else
3071
+ AryRangeAssignmentAst.new(input, interval, var, last_bracket.msb.expression.to_ast, last_bracket.lsb.to_ast, send(:rval).to_ast)
3072
+ end
2989
3073
  end
2990
3074
  end
2991
3075
 
@@ -3003,8 +3087,10 @@ module Idl
3003
3087
  if lsb.const_eval?(symtab) && msb.const_eval?(symtab) && write_value.const_eval?(symtab)
3004
3088
  true
3005
3089
  else
3006
- lhs_var = symtab.get(variable.name)
3007
- type_error "array #{variable.name} has not be declared" if lhs_var.nil?
3090
+ base_name = AstNode.extract_base_var_name(variable)
3091
+ type_error "Cannot determine base variable for #{variable.text_value}" if base_name.nil?
3092
+ lhs_var = symtab.get(base_name)
3093
+ type_error "array #{base_name} has not be declared" if lhs_var.nil?
3008
3094
 
3009
3095
  lhs_var.const_incompatible!
3010
3096
  false
@@ -3062,26 +3148,29 @@ module Idl
3062
3148
  def execute(symtab)
3063
3149
  return if variable.type(symtab).global?
3064
3150
 
3065
- var = symtab.get(variable.name)
3066
- internal_error "Variable #{variable.name} not found" if var.nil?
3067
-
3068
3151
  value_result = value_try do
3069
- var_val = variable.value(symtab)
3070
-
3071
3152
  msb_val = msb.value(symtab)
3072
3153
  lsb_val = lsb.value(symtab)
3073
3154
 
3074
3155
  type_error "MSB (#{msb_val}) is <= LSB (#{lsb_val})" if msb_val <= lsb_val
3075
3156
 
3076
3157
  rval_val = write_value.value(symtab)
3077
-
3078
3158
  mask = ((1 << (msb_val - lsb_val + 1)) - 1) << lsb_val
3079
3159
 
3080
- var.value = (var_val & ~mask) | ((rval_val << lsb_val) & mask)
3160
+ # Read current value, modify bits
3161
+ var_val = variable.value(symtab)
3162
+ var_val &= ~mask
3163
+ new_val = var_val | ((rval_val << lsb_val) & mask)
3164
+
3165
+ # Write back through the access chain
3166
+ AstNode.write_back_nested(variable, new_val, symtab)
3081
3167
  :ok
3082
3168
  end
3083
3169
  value_else(value_result) do
3084
- var.value = nil
3170
+ base_name = T.must(AstNode.extract_base_var_name(variable))
3171
+ v = symtab.get(base_name)
3172
+ internal_error "did not find array base" if v.nil?
3173
+ v.value = nil
3085
3174
  value_error "Either the range or right-hand side of an array range assignment is unknown"
3086
3175
  end
3087
3176
  end
@@ -3219,7 +3308,13 @@ module Idl
3219
3308
  var.value = bitfield_val
3220
3309
  elsif var.type.kind == :struct
3221
3310
  struct_val = id.value(symtab)
3222
- struct_val[@field_name] = rhs.value(symtab)
3311
+ value_result = value_try do
3312
+ struct_val[@field_name] = rhs.value(symtab)
3313
+ end
3314
+ value_else(value_result) do
3315
+ struct_val[@field_name] = nil
3316
+ value_error ""
3317
+ end
3223
3318
  else
3224
3319
  value_error "TODO: Field assignment execution"
3225
3320
  end
@@ -5275,6 +5370,10 @@ module Idl
5275
5370
  # @!macro value
5276
5371
  def value(symtab) = expression.value(symtab)
5277
5372
 
5373
+ def max_value(symtab) = expression.max_value(symtab)
5374
+
5375
+ def min_value(symtab) = expression.min_value(symtab)
5376
+
5278
5377
  # @!macro to_idl
5279
5378
  sig { override.returns(String) }
5280
5379
  def to_idl = "(#{expression.to_idl})"
@@ -5704,6 +5803,120 @@ module Idl
5704
5803
  end
5705
5804
  end
5706
5805
 
5806
+ # Generic syntax node for $name(arg, ...) — dispatches to the correct typed AstNode in to_ast.
5807
+ class DollarFunctionCallSyntaxNode < SyntaxNode
5808
+ def to_ast
5809
+ dollar_name = "$#{send(:name).text_value}"
5810
+ arg_nodes = dollar_arg_list_elements
5811
+ enum_type_name_validation = {
5812
+ 0 => {
5813
+ classes: [IdAst, UserTypeNameAst],
5814
+ description: "an identifier or user type name"
5815
+ }
5816
+ }
5817
+
5818
+ case dollar_name
5819
+ when "$width" then builtin_call_ast(dollar_name, arg_nodes, 1, WidthRevealAst)
5820
+ when "$signed" then builtin_call_ast(dollar_name, arg_nodes, 1, SignCastAst)
5821
+ when "$bits" then builtin_call_ast(dollar_name, arg_nodes, 1, BitsCastAst)
5822
+ when "$enum_size" then builtin_call_ast(dollar_name, arg_nodes, 1, EnumSizeAst, enum_type_name_validation)
5823
+ when "$enum_element_size" then builtin_call_ast(dollar_name, arg_nodes, 1, EnumElementSizeAst, enum_type_name_validation)
5824
+ when "$enum_to_a" then builtin_call_ast(dollar_name, arg_nodes, 1, EnumArrayCastAst, enum_type_name_validation)
5825
+ when "$enum" then builtin_call_ast(dollar_name, arg_nodes, 2, EnumCastAst, enum_type_name_validation)
5826
+ when "$array_size" then builtin_call_ast(dollar_name, arg_nodes, 1, ArraySizeAst)
5827
+ when "$array_includes?" then builtin_call_ast(dollar_name, arg_nodes, 2, ArrayIncludesAst)
5828
+ else
5829
+ ParseTimeDetectedTypeError.new(input, interval, "#{dollar_name} is not a builtin function")
5830
+ end
5831
+ end
5832
+
5833
+ private
5834
+
5835
+ def builtin_call_ast(dollar_name, arg_nodes, expected_arg_count, ast_class, arg_type_validations = {})
5836
+ if arg_nodes.size != expected_arg_count
5837
+ ParseTimeDetectedTypeError.new(input, interval, "#{dollar_name} expects #{expected_arg_count} argument#{expected_arg_count == 1 ? "" : "s"}; #{arg_nodes.size} given")
5838
+ else
5839
+ arg_asts = arg_nodes.first(expected_arg_count).map(&:to_ast)
5840
+
5841
+ arg_type_validations.each do |arg_index, validation|
5842
+ next if validation[:classes].any? { |klass| arg_asts[arg_index].is_a?(klass) }
5843
+
5844
+ return ParseTimeDetectedTypeError.new(
5845
+ input,
5846
+ interval,
5847
+ "#{dollar_name} expects argument #{arg_index + 1} to be #{validation[:description]}; #{builtin_arg_type_name(arg_asts[arg_index])} given"
5848
+ )
5849
+ end
5850
+
5851
+ ast_class.new(input, interval, *arg_asts)
5852
+ end
5853
+ end
5854
+
5855
+ def builtin_arg_type_name(arg_ast)
5856
+ arg_ast.class.name.split("::").last
5857
+ end
5858
+
5859
+ private
5860
+
5861
+ def dollar_arg_list_elements
5862
+ arg_list = send(:args)
5863
+ first = arg_list.first
5864
+ rest = arg_list.rest.elements.map { |e| e.expression }
5865
+ first.empty? ? rest : [first] + rest
5866
+ end
5867
+
5868
+ end
5869
+
5870
+ # Generic syntax node for $name (no parens) — creates a BuiltinVariableAst.
5871
+ class DollarVariableSyntaxNode < SyntaxNode
5872
+ def to_ast
5873
+ BuiltinVariableAst.new(input, interval, "$#{send(:name).text_value}")
5874
+ end
5875
+ end
5876
+
5877
+ # Syntax node for $name = expr — dispatches to PcAssignmentAst for $pc,
5878
+ class DollarVariableAssignmentSyntaxNode < SyntaxNode
5879
+ def to_ast
5880
+ dollar_name = "$#{send(:dollar_variable).send(:name).text_value}"
5881
+ rhs = send(:rval).to_ast
5882
+ case dollar_name
5883
+ when "$pc"
5884
+ PcAssignmentAst.new(input, interval, rhs)
5885
+ else
5886
+ ParseTimeDetectedTypeError.new(input, interval, "#{dollar_name} is not assignable")
5887
+ end
5888
+ end
5889
+ end
5890
+
5891
+ # AstNode for an error detected during to_ast. Always causes a type error
5892
+ class ParseTimeDetectedTypeError < AstNode
5893
+
5894
+ sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
5895
+ def const_eval?(symtab) = true
5896
+
5897
+ def initialize(input, interval, reason)
5898
+ super(input, interval, EMPTY_ARRAY)
5899
+ @reason = reason
5900
+ end
5901
+
5902
+ sig { override.params(symtab: SymbolTable, strict: T::Boolean).void }
5903
+ def type_check(symtab, strict:)
5904
+ type_error @reason
5905
+ end
5906
+
5907
+ sig { params(symtab: SymbolTable).returns(Type) }
5908
+ def type(symtab) = type_error(@reason)
5909
+
5910
+ sig { params(symtab: SymbolTable).returns(T.untyped) }
5911
+ def value(symtab) = value_error "Can't take value of a type error"
5912
+
5913
+ sig { override.returns(String) }
5914
+ def to_idl = text_value
5915
+
5916
+ sig { override.returns(T::Hash[String, T.untyped]) }
5917
+ def to_h = { "kind" => "ParseTimeDetectedTypeError", "reason" => @reason, "source" => source_yaml }
5918
+ end
5919
+
5707
5920
  class PostIncrementExpressionSyntaxNode < SyntaxNode
5708
5921
  def to_ast
5709
5922
  PostIncrementExpressionAst.new(input, interval, send(:rval).to_ast)
@@ -5848,7 +6061,9 @@ module Idl
5848
6061
  range = T.cast(obj.type(symtab), BitfieldType).range(@field_name)
5849
6062
  (T.cast(obj.value(symtab), Integer) >> range.first) & ((1 << range.size) - 1)
5850
6063
  elsif kind(symtab) == :struct
5851
- T.cast(obj.value(symtab), T::Hash[String, BasicValueRbType])[@field_name]
6064
+ field_val = T.cast(obj.value(symtab), T::Hash[String, BasicValueRbType])[@field_name]
6065
+ value_error "#{@field_name} is not known at compile-time" if field_val.nil?
6066
+ field_val
5852
6067
  else
5853
6068
  type_error "#{obj.text_value} is Not a bitfield."
5854
6069
  end
@@ -6263,6 +6478,34 @@ module Idl
6263
6478
  end
6264
6479
  end
6265
6480
 
6481
+ # @!macro max_value
6482
+ def max_value(symtab)
6483
+ value_result = value_try do
6484
+ cond = condition.value(symtab)
6485
+ return cond ? true_expression.max_value(symtab) : false_expression.max_value(symtab)
6486
+ end
6487
+ value_else(value_result) do
6488
+ t = true_expression.max_value(symtab)
6489
+ f = false_expression.max_value(symtab)
6490
+ return :unknown if t == :unknown || f == :unknown
6491
+ [t, f].max
6492
+ end
6493
+ end
6494
+
6495
+ # @!macro min_value
6496
+ def min_value(symtab)
6497
+ value_result = value_try do
6498
+ cond = condition.value(symtab)
6499
+ return cond ? true_expression.min_value(symtab) : false_expression.min_value(symtab)
6500
+ end
6501
+ value_else(value_result) do
6502
+ t = true_expression.min_value(symtab)
6503
+ f = false_expression.min_value(symtab)
6504
+ return :unknown if t == :unknown || f == :unknown
6505
+ [t, f].min
6506
+ end
6507
+ end
6508
+
6266
6509
  # @!macro to_idl
6267
6510
  sig { override.returns(String) }
6268
6511
  def to_idl = "#{condition.to_idl} ? #{true_expression.to_idl} : #{false_expression.to_idl}"
@@ -6354,10 +6597,10 @@ module Idl
6354
6597
 
6355
6598
  # @!macro execute
6356
6599
  def execute(symtab)
6357
- if action.is_a?(Declaration)
6600
+ if action.declaration?
6358
6601
  action.add_symbol(symtab)
6359
6602
  end
6360
- if action.is_a?(Executable)
6603
+ if action.executable?
6361
6604
  action.execute(symtab)
6362
6605
  end
6363
6606
  end
@@ -6410,7 +6653,7 @@ module Idl
6410
6653
  # @!macro type_check
6411
6654
  def type_check(symtab, strict:)
6412
6655
  action.type_check(symtab, strict:)
6413
- type_error "Cannot declare from a conditional statement" if action.is_a?(Declaration)
6656
+ type_error "Cannot declare from a conditional statement" if action.declaration?
6414
6657
 
6415
6658
  condition.type_check(symtab, strict:)
6416
6659
  type_error "condition is not boolean" unless condition.type(symtab).convertable_to?(:boolean)
@@ -6938,6 +7181,10 @@ module Idl
6938
7181
  # * U64 (Bits<64>)
6939
7182
  class BuiltinTypeNameAst < AstNode
6940
7183
 
7184
+ class Memo < T::Struct
7185
+ prop :bits_type, T::Hash[SymbolTable, T.nilable(Type)], default: {}
7186
+ end
7187
+
6941
7188
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
6942
7189
  def const_eval?(symtab) = (@type_name == "bits") ? bits_expression.const_eval?(symtab) : true
6943
7190
 
@@ -6950,6 +7197,7 @@ module Idl
6950
7197
  super(input, interval, [bits_expression])
6951
7198
  end
6952
7199
  @type_name = type_name
7200
+ @memo = Memo.new
6953
7201
  end
6954
7202
 
6955
7203
  # @!macro type_check
@@ -6970,21 +7218,19 @@ module Idl
6970
7218
  end
6971
7219
  end
6972
7220
 
6973
- def freeze_tree(symtab)
6974
- return if frozen?
6975
-
6976
- if @type_name == "Bits"
6977
- # precalculate size if possible
7221
+ sig { params(symtab: SymbolTable).returns(Type) }
7222
+ def bits_type(symtab)
7223
+ @memo.bits_type[symtab] ||=
6978
7224
  begin
6979
- value_try do
6980
- @bits_type = Type.new(:bits, width: bits_expression.value(symtab))
7225
+ t = T.let(nil, T.nilable(Type))
7226
+ value_result = value_try do
7227
+ t = Type.new(:bits, width: bits_expression.value(symtab))
6981
7228
  end
6982
- rescue TypeError
6983
- # ok, probably using a parameter
7229
+ value_else(value_result) do
7230
+ t = Type.new(:bits, width: :unknown, width_ast: bits_expression)
7231
+ end
7232
+ T.must(t)
6984
7233
  end
6985
- bits_expression&.freeze_tree(symtab)
6986
- end
6987
- freeze
6988
7234
  end
6989
7235
 
6990
7236
  # @!macro type
@@ -7008,14 +7254,7 @@ module Idl
7008
7254
  when "String"
7009
7255
  StringType
7010
7256
  when "Bits"
7011
- return @bits_type unless @bits_type.nil?
7012
-
7013
- value_result = value_try do
7014
- return Type.new(:bits, width: bits_expression.value(symtab))
7015
- end
7016
- value_else(value_result) do
7017
- return Type.new(:bits, width: :unknown, width_ast: bits_expression)
7018
- end
7257
+ bits_type(symtab)
7019
7258
  else
7020
7259
  internal_error "TODO: #{text_value}"
7021
7260
  end
@@ -7241,6 +7480,13 @@ module Idl
7241
7480
  class IntLiteralAst < AstNode
7242
7481
  include Rvalue
7243
7482
 
7483
+ class Memo < T::Struct
7484
+ prop :type, T.nilable(Type)
7485
+ prop :width, T.nilable(T.any(Integer, Symbol))
7486
+ prop :value, T.nilable(T.any(Integer, UnknownLiteral))
7487
+ prop :unsigned_value, T.nilable(T.any(Integer, UnknownLiteral))
7488
+ end
7489
+
7244
7490
  sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
7245
7491
  def const_eval?(symtab) = true
7246
7492
 
@@ -7248,19 +7494,11 @@ module Idl
7248
7494
  def initialize(input, interval, text)
7249
7495
  @text = text
7250
7496
  super(input, interval, EMPTY_ARRAY)
7497
+ @memo = Memo.new
7251
7498
  end
7252
7499
 
7253
7500
  def text_value = @text
7254
7501
 
7255
- def freeze_tree(global_symtab)
7256
- return if frozen?
7257
-
7258
- # initialize the cached objects
7259
- type(global_symtab)
7260
- value(global_symtab)
7261
- freeze
7262
- end
7263
-
7264
7502
  # @!macro type_check
7265
7503
  def type_check(symtab, strict:)
7266
7504
  if text_value.delete("_") =~ /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
@@ -7279,7 +7517,7 @@ module Idl
7279
7517
 
7280
7518
  # @!macro type
7281
7519
  def type(symtab)
7282
- return @type unless @type.nil?
7520
+ return @memo.type unless @memo.type.nil?
7283
7521
 
7284
7522
  case text_value.delete("_")
7285
7523
  when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
@@ -7295,7 +7533,7 @@ module Idl
7295
7533
 
7296
7534
  qualifiers = signed == "s" ? [:signed, :const] : [:const]
7297
7535
  qualifiers << :known unless T.must(value).include?("x")
7298
- @type =
7536
+ @memo.type =
7299
7537
  if width == :unknown
7300
7538
  Type.new(:bits, width:, max_width: 64, qualifiers:)
7301
7539
  else
@@ -7306,20 +7544,20 @@ module Idl
7306
7544
  signed = ::Regexp.last_match(3)
7307
7545
 
7308
7546
  qualifiers = signed == "s" ? [:signed, :const, :known] : [:const, :known]
7309
- @type = Type.new(:bits, width: width(symtab), qualifiers:)
7547
+ @memo.type = Type.new(:bits, width: width(symtab), qualifiers:)
7310
7548
  when /^([0-9]*)(s?)$/
7311
7549
  # basic decimal
7312
7550
  signed = ::Regexp.last_match(2)
7313
7551
 
7314
7552
  qualifiers = signed == "s" ? [:signed, :const, :known] : [:const, :known]
7315
- @type = Type.new(:bits, width: width(symtab), qualifiers:)
7553
+ @memo.type = Type.new(:bits, width: width(symtab), qualifiers:)
7316
7554
  else
7317
7555
  internal_error "Unhandled int value '#{text_value}'"
7318
7556
  end
7319
7557
  end
7320
7558
 
7321
7559
  def width(symtab)
7322
- return @width unless @width.nil?
7560
+ return @memo.width unless @memo.width.nil?
7323
7561
 
7324
7562
  text_value_no_underscores = text_value.delete("_")
7325
7563
 
@@ -7336,21 +7574,21 @@ module Idl
7336
7574
  else
7337
7575
  width = width.to_i
7338
7576
  end
7339
- @width = width
7577
+ @memo.width = width
7340
7578
  when /^0([bdx]?)([0-9a-fA-F]*)(s?)$/
7341
7579
  signed = ::Regexp.last_match(3)
7342
7580
 
7343
7581
  width = signed == "s" ? value(symtab).bit_length + 1 : value(symtab).bit_length
7344
7582
  width = 1 if width.zero? # happens when the literal is '0'
7345
7583
 
7346
- @width = width
7584
+ @memo.width = width
7347
7585
  when /^([0-9]*)(s?)$/
7348
7586
  signed = ::Regexp.last_match(3)
7349
7587
 
7350
7588
  width = signed == "s" ? value(symtab).bit_length + 1 : value(symtab).bit_length
7351
7589
  width = 1 if width.zero? # happens when the literal is '0'
7352
7590
 
7353
- @width = width
7591
+ @memo.width = width
7354
7592
  else
7355
7593
  internal_error "No match on int literal"
7356
7594
  end
@@ -7358,7 +7596,7 @@ module Idl
7358
7596
 
7359
7597
  # @!macro value
7360
7598
  def value(symtab)
7361
- return @value unless @value.nil?
7599
+ return @memo.value unless @memo.value.nil?
7362
7600
 
7363
7601
  if text_value.delete("_") =~ /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
7364
7602
  # verilog-style literal
@@ -7396,18 +7634,18 @@ module Idl
7396
7634
  end
7397
7635
  end
7398
7636
 
7399
- @value = v
7637
+ @memo.value = v
7400
7638
  else
7401
- @value = unsigned_value
7639
+ @memo.value = unsigned_value
7402
7640
  end
7403
7641
  end
7404
7642
 
7405
7643
 
7406
7644
  # @return [Integer] the unsigned value of this literal (i.e., treating it as unsigned even if the signed specifier is present)
7407
7645
  def unsigned_value
7408
- return @unsigned_value unless @unsigned_value.nil?
7646
+ return @memo.unsigned_value unless @memo.unsigned_value.nil?
7409
7647
 
7410
- @unsigned_value =
7648
+ @memo.unsigned_value =
7411
7649
  case text_value.delete("_")
7412
7650
  when /^((MXLEN)|([0-9]+))?'(s?)([bodh]?)(.*)$/
7413
7651
  # verilog-style literal
@@ -7487,15 +7725,6 @@ module Idl
7487
7725
  sig { override.returns(String) }
7488
7726
  def to_idl = text_value
7489
7727
 
7490
- sig { override.returns(String) }
7491
- def to_idl_verbose
7492
- if @width == :unknown
7493
- "MXLEN'#{@type.signed? ? 's' : ''}d#{unsigned_value}"
7494
- else
7495
- "#{@width}'#{@type.signed? ? 's' : ''}d#{unsigned_value}"
7496
- end
7497
- end
7498
-
7499
7728
  sig { returns(T::Boolean) }
7500
7729
  def signed?
7501
7730
  case text_value.delete("_")
@@ -7900,7 +8129,7 @@ module Idl
7900
8129
  stmts.each do |s|
7901
8130
  if s.is_a?(Returns)
7902
8131
  return s.return_type(symtab)
7903
- elsif s.action.is_a?(Declaration)
8132
+ elsif s.action.declaration?
7904
8133
  s.action.add_symbol(symtab)
7905
8134
  end
7906
8135
  end
@@ -9284,15 +9513,6 @@ module Idl
9284
9513
  @memo = Memo.new
9285
9514
  end
9286
9515
 
9287
- def freeze_tree(symtab)
9288
- return if frozen?
9289
-
9290
- type_error "CSR '#{@csr_name}' is not defined" unless symtab.csr?(@csr_name)
9291
-
9292
- @children.each { |child| child.freeze_tree(symtab) }
9293
- freeze
9294
- end
9295
-
9296
9516
  # @!macro type
9297
9517
  def type(symtab) = @memo.type ||= CsrType.new(csr_def(symtab))
9298
9518