idlc 0.1.2 → 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 +340 -95
- 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 +50 -17
- 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 +15 -10
- 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
|
|
@@ -512,11 +567,11 @@ module Idl
|
|
|
512
567
|
# end: <0-indexed position of the ending character in the input>
|
|
513
568
|
sig { returns(T::Hash[String, T.untyped]) }
|
|
514
569
|
def source_yaml
|
|
515
|
-
base_offset =
|
|
570
|
+
base_offset = source_starting_offset
|
|
516
571
|
interval_begin = T.must(interval).begin
|
|
517
572
|
interval_end = T.must(interval).size == 0 ? T.must(interval).begin + 1 : T.must(interval).end
|
|
518
573
|
|
|
519
|
-
lfo =
|
|
574
|
+
lfo = source_line_file_offsets
|
|
520
575
|
if lfo
|
|
521
576
|
# Map an IDL-string position to a file byte offset using the per-line table.
|
|
522
577
|
# Each entry lfo[i] is the file offset of the first character of IDL line i.
|
|
@@ -539,12 +594,23 @@ module Idl
|
|
|
539
594
|
end
|
|
540
595
|
|
|
541
596
|
{
|
|
542
|
-
"file" =>
|
|
597
|
+
"file" => T.must(input_file).to_s,
|
|
543
598
|
"begin" => file_begin,
|
|
544
599
|
"end" => file_end
|
|
545
600
|
}
|
|
546
601
|
end
|
|
547
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
|
+
|
|
548
614
|
private
|
|
549
615
|
|
|
550
616
|
# Given an IDL-string position +pos+ and the per-line file-offset table +lfo+,
|
|
@@ -673,7 +739,10 @@ module Idl
|
|
|
673
739
|
module Executable
|
|
674
740
|
extend T::Sig
|
|
675
741
|
extend T::Helpers
|
|
676
|
-
|
|
742
|
+
abstract!
|
|
743
|
+
|
|
744
|
+
sig { returns(T::Boolean).checked(:never) }
|
|
745
|
+
def executable? = true
|
|
677
746
|
|
|
678
747
|
# @!macro [new] execute
|
|
679
748
|
# "execute" the statement by updating the variables in the symbol table
|
|
@@ -860,7 +929,10 @@ module Idl
|
|
|
860
929
|
module Declaration
|
|
861
930
|
extend T::Sig
|
|
862
931
|
extend T::Helpers
|
|
863
|
-
|
|
932
|
+
abstract!
|
|
933
|
+
|
|
934
|
+
sig { returns(T::Boolean).checked(:never) }
|
|
935
|
+
def declaration? = true
|
|
864
936
|
|
|
865
937
|
# @!macro [new] add_symbol
|
|
866
938
|
# Add symbol(s) at the outermost scope of the symbol table
|
|
@@ -1339,9 +1411,13 @@ module Idl
|
|
|
1339
1411
|
|
|
1340
1412
|
enums.each { |g| g.add_symbol(symtab); }
|
|
1341
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) }
|
|
1342
1419
|
globals.each { |g| g.add_symbol(symtab) }
|
|
1343
1420
|
structs.each { |g| g.add_symbol(symtab) }
|
|
1344
|
-
functions.each { |g| g.add_symbol(symtab) }
|
|
1345
1421
|
end
|
|
1346
1422
|
|
|
1347
1423
|
# replaces an include statement with the ast in that file, making
|
|
@@ -1418,7 +1494,9 @@ module Idl
|
|
|
1418
1494
|
end
|
|
1419
1495
|
end
|
|
1420
1496
|
|
|
1421
|
-
IsaAst.new(input, interval, kids)
|
|
1497
|
+
node = IsaAst.new(input, interval, kids)
|
|
1498
|
+
node.set_input_file(yaml.fetch("source").fetch("file"))
|
|
1499
|
+
node
|
|
1422
1500
|
end
|
|
1423
1501
|
end
|
|
1424
1502
|
|
|
@@ -1493,12 +1571,6 @@ module Idl
|
|
|
1493
1571
|
end
|
|
1494
1572
|
end
|
|
1495
1573
|
|
|
1496
|
-
class ArraySizeSyntaxNode < SyntaxNode
|
|
1497
|
-
def to_ast
|
|
1498
|
-
ArraySizeAst.new(input, interval, send(:expression).to_ast)
|
|
1499
|
-
end
|
|
1500
|
-
end
|
|
1501
|
-
|
|
1502
1574
|
class ArraySizeAst < AstNode
|
|
1503
1575
|
include Rvalue
|
|
1504
1576
|
|
|
@@ -1560,25 +1632,21 @@ module Idl
|
|
|
1560
1632
|
end
|
|
1561
1633
|
|
|
1562
1634
|
|
|
1563
|
-
class EnumSizeSyntaxNode < SyntaxNode
|
|
1564
|
-
def to_ast
|
|
1565
|
-
EnumSizeAst.new(input, interval, send(:type_name).to_ast)
|
|
1566
|
-
end
|
|
1567
|
-
end
|
|
1568
|
-
|
|
1569
1635
|
# represents the builtin that returns the nymber of elements in an enum class
|
|
1570
1636
|
#
|
|
1571
1637
|
# $enum_size(XRegWidth) #=> 2
|
|
1572
1638
|
class EnumSizeAst < AstNode
|
|
1573
1639
|
include Rvalue
|
|
1574
1640
|
|
|
1575
|
-
def enum_class = children
|
|
1641
|
+
def enum_class = children.fetch(0)
|
|
1576
1642
|
|
|
1577
1643
|
sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
|
|
1578
1644
|
def const_eval?(symtab) = true
|
|
1579
1645
|
|
|
1646
|
+
sig { params(input: T.nilable(String), interval: T.nilable(T::Range[Integer]), enum_class_name: T.any(IdAst, UserTypeNameAst)).void }
|
|
1580
1647
|
def initialize(input, interval, enum_class_name)
|
|
1581
|
-
|
|
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])
|
|
1582
1650
|
end
|
|
1583
1651
|
|
|
1584
1652
|
def type_check(symtab, strict:)
|
|
@@ -1615,17 +1683,11 @@ module Idl
|
|
|
1615
1683
|
interval = interval_from_source_yaml(yaml.fetch("source"))
|
|
1616
1684
|
EnumSizeAst.new(
|
|
1617
1685
|
input, interval,
|
|
1618
|
-
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)
|
|
1619
1687
|
)
|
|
1620
1688
|
end
|
|
1621
1689
|
end
|
|
1622
1690
|
|
|
1623
|
-
class EnumElementSizeSyntaxNode < SyntaxNode
|
|
1624
|
-
def to_ast
|
|
1625
|
-
EnumElementSizeAst.new(input, interval, send(:type_name).to_ast)
|
|
1626
|
-
end
|
|
1627
|
-
end
|
|
1628
|
-
|
|
1629
1691
|
# represents the builtin that returns the bitwidth of an element in an enum class
|
|
1630
1692
|
#
|
|
1631
1693
|
# $enum_element_size(PrivilegeMode) #=> 3
|
|
@@ -1637,9 +1699,10 @@ module Idl
|
|
|
1637
1699
|
sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
|
|
1638
1700
|
def const_eval?(symtab) = true
|
|
1639
1701
|
|
|
1640
|
-
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 }
|
|
1641
1703
|
def initialize(input, interval, enum_class_name)
|
|
1642
|
-
|
|
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])
|
|
1643
1706
|
end
|
|
1644
1707
|
|
|
1645
1708
|
def type_check(symtab, strict:)
|
|
@@ -1677,12 +1740,6 @@ module Idl
|
|
|
1677
1740
|
end
|
|
1678
1741
|
end
|
|
1679
1742
|
|
|
1680
|
-
class EnumCastSyntaxNode < SyntaxNode
|
|
1681
|
-
def to_ast
|
|
1682
|
-
EnumCastAst.new(input, interval, send(:type_name).to_ast, send(:expression).to_ast)
|
|
1683
|
-
end
|
|
1684
|
-
end
|
|
1685
|
-
|
|
1686
1743
|
class EnumCastAst < AstNode
|
|
1687
1744
|
include Rvalue
|
|
1688
1745
|
|
|
@@ -1690,22 +1747,23 @@ module Idl
|
|
|
1690
1747
|
def const_eval?(symtab) = true
|
|
1691
1748
|
|
|
1692
1749
|
# @return [UserTypeAst] Enum name
|
|
1693
|
-
def enum_name = @children
|
|
1750
|
+
def enum_name = @children.fetch(0)
|
|
1694
1751
|
|
|
1695
1752
|
# @return [Rvalue] Value expression
|
|
1696
|
-
def expression = @children
|
|
1753
|
+
def expression = @children.fetch(1)
|
|
1697
1754
|
|
|
1698
1755
|
sig {
|
|
1699
1756
|
params(
|
|
1700
1757
|
input: T.nilable(String),
|
|
1701
1758
|
interval: T.nilable(T::Range[Integer]),
|
|
1702
|
-
type_name: UserTypeNameAst,
|
|
1759
|
+
type_name: T.any(IdAst, UserTypeNameAst),
|
|
1703
1760
|
expression: RvalueAst
|
|
1704
1761
|
)
|
|
1705
1762
|
.void
|
|
1706
1763
|
}
|
|
1707
1764
|
def initialize(input, interval, type_name, expression)
|
|
1708
|
-
|
|
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])
|
|
1709
1767
|
end
|
|
1710
1768
|
|
|
1711
1769
|
def type_check(symtab, strict:)
|
|
@@ -1758,26 +1816,21 @@ module Idl
|
|
|
1758
1816
|
end
|
|
1759
1817
|
end
|
|
1760
1818
|
|
|
1761
|
-
class EnumArrayCastSyntaxNode < SyntaxNode
|
|
1762
|
-
def to_ast
|
|
1763
|
-
EnumArrayCastAst.new(input, interval, send(:type_name).to_ast)
|
|
1764
|
-
end
|
|
1765
|
-
end
|
|
1766
|
-
|
|
1767
1819
|
# represents the builtin that returns an array with all elements of an Enum type
|
|
1768
1820
|
#
|
|
1769
1821
|
# $enum_to_a(PrivilegeMode) #=> [3, 1, 1, 0, 5, 4]
|
|
1770
1822
|
class EnumArrayCastAst < AstNode
|
|
1771
1823
|
include Rvalue
|
|
1772
1824
|
|
|
1773
|
-
def enum_class = children
|
|
1825
|
+
def enum_class = children.fetch(0)
|
|
1774
1826
|
|
|
1775
1827
|
sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
|
|
1776
1828
|
def const_eval?(symtab) = true
|
|
1777
1829
|
|
|
1778
|
-
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 }
|
|
1779
1831
|
def initialize(input, interval, enum_class_name)
|
|
1780
|
-
|
|
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])
|
|
1781
1834
|
end
|
|
1782
1835
|
|
|
1783
1836
|
def type_check(symtab, strict:)
|
|
@@ -2479,7 +2532,12 @@ module Idl
|
|
|
2479
2532
|
|
|
2480
2533
|
sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
|
|
2481
2534
|
def const_eval?(symtab)
|
|
2482
|
-
|
|
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)
|
|
2483
2541
|
false
|
|
2484
2542
|
else
|
|
2485
2543
|
var.const_eval?(symtab) && index.const_eval?(symtab)
|
|
@@ -2544,7 +2602,12 @@ module Idl
|
|
|
2544
2602
|
if var.type(symtab).integral?
|
|
2545
2603
|
(var_val >> index.value(symtab)) & 1
|
|
2546
2604
|
else
|
|
2547
|
-
|
|
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)
|
|
2548
2611
|
|
|
2549
2612
|
# internal_error "Not an array" unless ary.type.kind == :array
|
|
2550
2613
|
|
|
@@ -2589,7 +2652,12 @@ module Idl
|
|
|
2589
2652
|
sig { override.params(symtab: SymbolTable).returns(T::Boolean) }
|
|
2590
2653
|
def const_eval?(symtab)
|
|
2591
2654
|
v = var
|
|
2592
|
-
|
|
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)
|
|
2593
2661
|
false
|
|
2594
2662
|
else
|
|
2595
2663
|
v.const_eval?(symtab) && msb.const_eval?(symtab).const_eval? && lsb.const_eval?(symtab)
|
|
@@ -2853,12 +2921,6 @@ module Idl
|
|
|
2853
2921
|
end
|
|
2854
2922
|
end
|
|
2855
2923
|
|
|
2856
|
-
class AryElementAssignmentSyntaxNode < SyntaxNode
|
|
2857
|
-
def to_ast
|
|
2858
|
-
AryElementAssignmentAst.new(input, interval, send(:var).to_ast, send(:idx).to_ast, send(:rval).to_ast)
|
|
2859
|
-
end
|
|
2860
|
-
end
|
|
2861
|
-
|
|
2862
2924
|
# represents an array element assignment
|
|
2863
2925
|
#
|
|
2864
2926
|
# for example:
|
|
@@ -2873,8 +2935,10 @@ module Idl
|
|
|
2873
2935
|
if idx.const_eval?(symtab) && rhs.const_eval?(symtab)
|
|
2874
2936
|
true
|
|
2875
2937
|
else
|
|
2876
|
-
|
|
2877
|
-
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?
|
|
2878
2942
|
|
|
2879
2943
|
lhs_var.const_incompatible!
|
|
2880
2944
|
false
|
|
@@ -2940,13 +3004,15 @@ module Idl
|
|
|
2940
3004
|
value_error "right-hand side of array element assignment is unknown"
|
|
2941
3005
|
end
|
|
2942
3006
|
when :bits
|
|
2943
|
-
var = symtab.get(lhs.text_value)
|
|
2944
3007
|
value_result = value_try do
|
|
2945
|
-
|
|
2946
|
-
|
|
3008
|
+
new_element = (lhs.value(symtab) & ~0) | ((rhs.value(symtab) & 1) << idx.value(symtab))
|
|
3009
|
+
AstNode.write_back_nested(lhs, new_element, symtab)
|
|
2947
3010
|
end
|
|
2948
3011
|
value_else(value_result) do
|
|
2949
|
-
|
|
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
|
|
2950
3016
|
end
|
|
2951
3017
|
else
|
|
2952
3018
|
internal_error "unexpected type for array element assignment"
|
|
@@ -2983,7 +3049,27 @@ module Idl
|
|
|
2983
3049
|
|
|
2984
3050
|
class AryRangeAssignmentSyntaxNode < SyntaxNode
|
|
2985
3051
|
def to_ast
|
|
2986
|
-
|
|
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
|
|
2987
3073
|
end
|
|
2988
3074
|
end
|
|
2989
3075
|
|
|
@@ -3001,8 +3087,10 @@ module Idl
|
|
|
3001
3087
|
if lsb.const_eval?(symtab) && msb.const_eval?(symtab) && write_value.const_eval?(symtab)
|
|
3002
3088
|
true
|
|
3003
3089
|
else
|
|
3004
|
-
|
|
3005
|
-
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?
|
|
3006
3094
|
|
|
3007
3095
|
lhs_var.const_incompatible!
|
|
3008
3096
|
false
|
|
@@ -3060,26 +3148,29 @@ module Idl
|
|
|
3060
3148
|
def execute(symtab)
|
|
3061
3149
|
return if variable.type(symtab).global?
|
|
3062
3150
|
|
|
3063
|
-
var = symtab.get(variable.name)
|
|
3064
|
-
internal_error "Variable #{variable.name} not found" if var.nil?
|
|
3065
|
-
|
|
3066
3151
|
value_result = value_try do
|
|
3067
|
-
var_val = variable.value(symtab)
|
|
3068
|
-
|
|
3069
3152
|
msb_val = msb.value(symtab)
|
|
3070
3153
|
lsb_val = lsb.value(symtab)
|
|
3071
3154
|
|
|
3072
3155
|
type_error "MSB (#{msb_val}) is <= LSB (#{lsb_val})" if msb_val <= lsb_val
|
|
3073
3156
|
|
|
3074
3157
|
rval_val = write_value.value(symtab)
|
|
3075
|
-
|
|
3076
3158
|
mask = ((1 << (msb_val - lsb_val + 1)) - 1) << lsb_val
|
|
3077
3159
|
|
|
3078
|
-
|
|
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)
|
|
3079
3167
|
:ok
|
|
3080
3168
|
end
|
|
3081
3169
|
value_else(value_result) do
|
|
3082
|
-
|
|
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
|
|
3083
3174
|
value_error "Either the range or right-hand side of an array range assignment is unknown"
|
|
3084
3175
|
end
|
|
3085
3176
|
end
|
|
@@ -3217,7 +3308,13 @@ module Idl
|
|
|
3217
3308
|
var.value = bitfield_val
|
|
3218
3309
|
elsif var.type.kind == :struct
|
|
3219
3310
|
struct_val = id.value(symtab)
|
|
3220
|
-
|
|
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
|
|
3221
3318
|
else
|
|
3222
3319
|
value_error "TODO: Field assignment execution"
|
|
3223
3320
|
end
|
|
@@ -5273,6 +5370,10 @@ module Idl
|
|
|
5273
5370
|
# @!macro value
|
|
5274
5371
|
def value(symtab) = expression.value(symtab)
|
|
5275
5372
|
|
|
5373
|
+
def max_value(symtab) = expression.max_value(symtab)
|
|
5374
|
+
|
|
5375
|
+
def min_value(symtab) = expression.min_value(symtab)
|
|
5376
|
+
|
|
5276
5377
|
# @!macro to_idl
|
|
5277
5378
|
sig { override.returns(String) }
|
|
5278
5379
|
def to_idl = "(#{expression.to_idl})"
|
|
@@ -5702,6 +5803,120 @@ module Idl
|
|
|
5702
5803
|
end
|
|
5703
5804
|
end
|
|
5704
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
|
+
|
|
5705
5920
|
class PostIncrementExpressionSyntaxNode < SyntaxNode
|
|
5706
5921
|
def to_ast
|
|
5707
5922
|
PostIncrementExpressionAst.new(input, interval, send(:rval).to_ast)
|
|
@@ -5846,7 +6061,9 @@ module Idl
|
|
|
5846
6061
|
range = T.cast(obj.type(symtab), BitfieldType).range(@field_name)
|
|
5847
6062
|
(T.cast(obj.value(symtab), Integer) >> range.first) & ((1 << range.size) - 1)
|
|
5848
6063
|
elsif kind(symtab) == :struct
|
|
5849
|
-
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
|
|
5850
6067
|
else
|
|
5851
6068
|
type_error "#{obj.text_value} is Not a bitfield."
|
|
5852
6069
|
end
|
|
@@ -6261,6 +6478,34 @@ module Idl
|
|
|
6261
6478
|
end
|
|
6262
6479
|
end
|
|
6263
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
|
+
|
|
6264
6509
|
# @!macro to_idl
|
|
6265
6510
|
sig { override.returns(String) }
|
|
6266
6511
|
def to_idl = "#{condition.to_idl} ? #{true_expression.to_idl} : #{false_expression.to_idl}"
|
|
@@ -6352,10 +6597,10 @@ module Idl
|
|
|
6352
6597
|
|
|
6353
6598
|
# @!macro execute
|
|
6354
6599
|
def execute(symtab)
|
|
6355
|
-
if action.
|
|
6600
|
+
if action.declaration?
|
|
6356
6601
|
action.add_symbol(symtab)
|
|
6357
6602
|
end
|
|
6358
|
-
if action.
|
|
6603
|
+
if action.executable?
|
|
6359
6604
|
action.execute(symtab)
|
|
6360
6605
|
end
|
|
6361
6606
|
end
|
|
@@ -6408,7 +6653,7 @@ module Idl
|
|
|
6408
6653
|
# @!macro type_check
|
|
6409
6654
|
def type_check(symtab, strict:)
|
|
6410
6655
|
action.type_check(symtab, strict:)
|
|
6411
|
-
type_error "Cannot declare from a conditional statement" if action.
|
|
6656
|
+
type_error "Cannot declare from a conditional statement" if action.declaration?
|
|
6412
6657
|
|
|
6413
6658
|
condition.type_check(symtab, strict:)
|
|
6414
6659
|
type_error "condition is not boolean" unless condition.type(symtab).convertable_to?(:boolean)
|
|
@@ -7884,7 +8129,7 @@ module Idl
|
|
|
7884
8129
|
stmts.each do |s|
|
|
7885
8130
|
if s.is_a?(Returns)
|
|
7886
8131
|
return s.return_type(symtab)
|
|
7887
|
-
elsif s.action.
|
|
8132
|
+
elsif s.action.declaration?
|
|
7888
8133
|
s.action.add_symbol(symtab)
|
|
7889
8134
|
end
|
|
7890
8135
|
end
|