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.
- checksums.yaml +4 -4
- data/lib/idlc/ast.rb +404 -184
- data/lib/idlc/cli.rb +11 -2
- data/lib/idlc/idl.treetop +39 -62
- data/lib/idlc/idl_parser.rb +1810 -2452
- data/lib/idlc/passes/find_src_registers.rb +58 -18
- data/lib/idlc/passes/prune.rb +54 -18
- data/lib/idlc/passes/reachable_exceptions.rb +6 -6
- data/lib/idlc/passes/reachable_functions.rb +2 -2
- data/lib/idlc/symbol_table.rb +50 -9
- data/lib/idlc/syntax_node.rb +2 -8
- data/lib/idlc/type.rb +16 -11
- data/lib/idlc/version.rb +1 -1
- data/lib/idlc.rb +53 -29
- metadata +3 -6
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
|
-
|
|
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
|
-
|
|
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 +
|
|
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
|
-
"#{
|
|
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 =
|
|
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 =
|
|
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" =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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),
|
|
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
|
-
|
|
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
|
|
1750
|
+
def enum_name = @children.fetch(0)
|
|
1700
1751
|
|
|
1701
1752
|
# @return [Rvalue] Value expression
|
|
1702
|
-
def expression = @children
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
#
|
|
2199
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2879
|
-
type_error "
|
|
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
|
-
|
|
2948
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3007
|
-
type_error "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
6600
|
+
if action.declaration?
|
|
6358
6601
|
action.add_symbol(symtab)
|
|
6359
6602
|
end
|
|
6360
|
-
if action.
|
|
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.
|
|
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
|
-
|
|
6974
|
-
|
|
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
|
-
|
|
6980
|
-
|
|
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
|
-
|
|
6983
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|