idlc 0.1.1

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/type.rb ADDED
@@ -0,0 +1,992 @@
1
+ # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
2
+ # SPDX-License-Identifier: BSD-3-Clause-Clear
3
+
4
+ # typed: true
5
+ # frozen_string_literal: true
6
+
7
+ require "sorbet-runtime"
8
+
9
+ module Idl
10
+
11
+ class AstNode; end
12
+ class EnumDefinitionAst < AstNode; end
13
+ class Type; end
14
+ class EnumerationType < Type; end
15
+ module Csr
16
+ include Kernel
17
+ end
18
+
19
+ # Data types
20
+ class Type
21
+ extend T::Sig
22
+
23
+ KINDS = [
24
+ :void, # empty
25
+ :boolean, # true or false, not compatible with bits/int/xreg
26
+ :bits, # integer with compile-time-known bit width
27
+ :enum, # enumeration class
28
+ :enum_ref, # reference to an enumeration element, convertible to int and/or Bits<bit_width(MAX_ENUM_VALUE)>
29
+ :bitfield, # bitfield, convertible to int and/or Bits<width>
30
+ :struct, # structure class
31
+ :array, # array of other types
32
+ :tuple, # tuple of other dissimilar types
33
+ :function, # function
34
+ :csr, # a CSR register type
35
+ :dontcare, # matches everything
36
+ :string # fixed-length character string
37
+ ].freeze
38
+ QUALIFIERS = [
39
+ :const,
40
+ :signed,
41
+ :global,
42
+ :known
43
+ ].freeze
44
+
45
+ # true for any type that can generally be treated as a scalar integer
46
+ sig { returns(T::Boolean) }
47
+ def integral?
48
+ @kind == :bits
49
+ end
50
+
51
+ def ==(other)
52
+ return false unless other.is_a?(Type)
53
+
54
+ case other.kind
55
+ when :bits
56
+ @kind == :bits && @width == other.width
57
+ when :enum_ref
58
+ @kind == :enum_ref && T.must(@enum_class).name == other.name
59
+ else
60
+ raise "TODO: Type == for #{other.kind}"
61
+ end
62
+ end
63
+
64
+ def runtime?
65
+ if @kind == :array
66
+ T.must(@sub_type).runtime?
67
+ else
68
+ @kind == :bits && @width == :unknown
69
+ end
70
+ end
71
+
72
+ def default
73
+ case @kind
74
+ when :bits, :bitfield
75
+ 0
76
+ when :boolean
77
+ false
78
+ when :array
79
+ if @width == :unknown
80
+ Array.new
81
+ else
82
+ Array.new(T.cast(@width, Integer), sub_type.default)
83
+ end
84
+ when :string
85
+ ""
86
+ when :enum_ref
87
+ T.must(@enum_class).element_values.min
88
+ when :enum
89
+ raise "?"
90
+ else
91
+ raise "No default for #{@kind}"
92
+ end
93
+ end
94
+
95
+ sig { returns(Symbol) }
96
+ attr_reader :kind
97
+
98
+ sig { returns(T::Array[Symbol]) }
99
+ attr_reader :qualifiers
100
+
101
+ sig { returns(T.any(Integer, Symbol)) }
102
+ def width = T.must(@width)
103
+
104
+ sig { returns(T.nilable(AstNode)) }
105
+ attr_reader :width_ast
106
+
107
+ sig { returns(T.nilable(Integer)) }
108
+ attr_reader :max_width
109
+
110
+ sig { returns(Type) }
111
+ def sub_type = T.must(@sub_type)
112
+
113
+ sig { returns(T::Array[Type]) }
114
+ def tuple_types = T.must(@tuple_types)
115
+
116
+ sig { returns(EnumerationType) }
117
+ def enum_class = T.must(@enum_class)
118
+
119
+ def qualify(qualifier)
120
+ @qualifiers << qualifier
121
+ @qualifiers.uniq!
122
+ self
123
+ end
124
+
125
+ def self.from_typename(type_name, cfg_arch)
126
+ case type_name
127
+ when "XReg"
128
+ return Type.new(:bits, width: cfg_arch.param_values.key?("MXLEN") ? cfg_arch.param_values.fetch("MXLEN") : :unknown, max_width: 64)
129
+ when /Bits<((?:0x)?[0-9a-fA-F]+)>/
130
+ Type.new(:bits, width: $1.to_i)
131
+ end
132
+ end
133
+
134
+ sig {
135
+ params(
136
+ kind: Symbol,
137
+ qualifiers: T::Array[Symbol],
138
+ width: T.nilable(T.any(Integer, Symbol)),
139
+ width_ast: T.nilable(AstNode),
140
+ max_width: T.nilable(Integer),
141
+ sub_type: T.nilable(Type),
142
+ name: T.nilable(String),
143
+ tuple_types: T.nilable(T::Array[Type]),
144
+ return_type: T.nilable(Type),
145
+ enum_class: T.nilable(EnumerationType),
146
+ csr: T.nilable(Csr)
147
+ )
148
+ .void
149
+ }
150
+ def initialize(kind, qualifiers: [], width: nil, width_ast: nil, max_width: nil, sub_type: nil, name: nil, tuple_types: nil, return_type: nil, enum_class: nil, csr: nil)
151
+ raise "Invalid kind '#{kind}'" unless KINDS.include?(kind)
152
+
153
+ @kind = kind
154
+ raise "Invalid qualifier" unless qualifiers.intersection(QUALIFIERS) == qualifiers
155
+
156
+ @qualifiers = qualifiers
157
+ # raise "#{width.class.name}" if (kind == :bits && !width.is_a?(Integer))
158
+
159
+ raise "Should be a FunctionType" if kind == :function && !self.is_a?(FunctionType)
160
+
161
+ @width = width
162
+ @width_ast = width_ast
163
+ @max_width = max_width
164
+ @sub_type = sub_type
165
+ raise "Tuples need a type list" if kind == :tuple && tuple_types.nil?
166
+ @tuple_types = tuple_types
167
+ @enum_class = enum_class
168
+ @name = name
169
+ if kind == :bits
170
+ raise "Bits type must have width" unless @width
171
+ raise "Bits type must have positive width (has #{@width})" unless @width == :unknown || T.cast(@width, Integer).positive?
172
+ end
173
+ if kind == :enum
174
+ raise "Enum type must have width" unless @width
175
+ end
176
+ if kind == :array && width != 0
177
+ raise "Array must have a subtype" unless @sub_type
178
+ end
179
+ if kind == :csr
180
+ raise "CSR type must have a csr argument" if csr.nil?
181
+
182
+ @csr = csr
183
+ raise "CSR types must have a width" if width.nil?
184
+
185
+ @width = width
186
+ end
187
+ end
188
+ TYPE_FROM_KIND = [:boolean, :void, :dontcare].map { |k| [k, Type.new(k)] }.to_h.freeze
189
+
190
+ def clone
191
+ Type.new(
192
+ @kind,
193
+ qualifiers: @qualifiers.map(&:clone),
194
+ width: @width,
195
+ sub_type: @sub_type&.clone,
196
+ name: @name.dup,
197
+ tuple_types: @tuple_types&.map(&:clone),
198
+ enum_class: @enum_class&.clone,
199
+ csr: @csr
200
+ )
201
+ end
202
+
203
+ # returns true if 'type' can be compared (e.g., >=, <, etc) to self
204
+ # 'type' can be a Type object or a kind (as a Symbol)
205
+ def comparable_to?(type)
206
+ if type.is_a?(Symbol)
207
+ raise "#{type} is not a kind" unless KINDS.include?(type)
208
+
209
+ type = Type.new(type)
210
+ end
211
+
212
+ case @kind
213
+ when :boolean
214
+ return type.kind == :boolean
215
+ when :enum_ref
216
+ return \
217
+ (type.kind == :enum_ref && type.enum_class.name == T.must(@enum_class).name) \
218
+ || (type.kind == :enum && type.name == T.must(@enum_class).name)
219
+ when :bits
220
+ return type.convertable_to?(self) && (signed? == type.signed?)
221
+ when :enum
222
+ return type.convertable_to?(:bits)
223
+ when :function
224
+ # functions are not comparable to anything
225
+ return false
226
+ when :csr
227
+ return ((type.kind == :csr) && (type.csr.name == @csr.name)) ||
228
+ type.convertable_to?(Type.new(:bits, width: type.csr.width))
229
+ when :string
230
+ return type.kind == :string
231
+ else
232
+ raise "unimplemented #{@kind}"
233
+ end
234
+ end
235
+
236
+ # returns true if identical to type, excluding qualifiers
237
+ def equal_to?(type)
238
+ if type.is_a?(Symbol)
239
+ raise "#{type} is not a kind" unless KINDS.include?(type)
240
+
241
+ type = TYPE_FROM_KIND[type]
242
+ end
243
+
244
+ case @kind
245
+ when :boolean
246
+ type.kind == :boolean
247
+ when :enum_ref
248
+ type.kind == :enum_ref && type.name == T.must(@enum_class).name
249
+ when :dontcare
250
+ true
251
+ when :bits
252
+ type.kind == :bits && type.width == @width
253
+ when :string
254
+ type.kind == :string && type.width == @width
255
+ when :array
256
+ type.kind == :array && type.sub_type.equal_to?(@sub_type)
257
+ when :struct
258
+ type.kind == :struct && (T.cast(type, StructType).type_name == T.cast(self, StructType).type_name)
259
+ else
260
+ raise "unimplemented type '#{@kind}'"
261
+ end
262
+ end
263
+
264
+ # given an N-dimensional array type, return the primitive type
265
+ def ary_type(ary)
266
+ if ary.sub_type == :array
267
+ ary_type(ary.sub_type)
268
+ else
269
+ ary.sub_type
270
+ end
271
+ end
272
+
273
+ # returns true if self can be converted to 'type'
274
+ # 'type' can be a Type object or a kind (as a Symbol)
275
+ def convertable_to?(type)
276
+ if type.is_a?(Symbol)
277
+ raise "#{type} is not a kind" unless KINDS.include?(type)
278
+
279
+ type = TYPE_FROM_KIND[type]
280
+ end
281
+
282
+ case @kind
283
+ when :boolean
284
+ return type.kind == :boolean
285
+ when :enum_ref
286
+ return \
287
+ (type.kind == :enum && type.name == T.must(@enum_class).name) || \
288
+ (type.kind == :enum_ref && type.enum_class.name == T.must(@enum_class).name)
289
+ when :dontcare
290
+ return true
291
+ when :bits
292
+ if type.kind == :enum_ref
293
+ warn "You seem to be missing an $enum cast"
294
+ return false
295
+ end
296
+ return type.kind == :bits || type.kind == :bitfield
297
+ when :enum
298
+ if type.kind == :bits
299
+ return false
300
+ # return (type.width == :unknown) || (width <= type.width)
301
+ elsif type.kind == :enum
302
+ return type.enum_class == enum_class
303
+ else
304
+ return false
305
+ end
306
+ when :tuple
307
+ is_tuple_of_same_size = (type.kind == :tuple) && (T.must(@tuple_types).size == type.tuple_types.size)
308
+ if is_tuple_of_same_size
309
+ T.must(@tuple_types).each_index do |i|
310
+ unless T.must(@tuple_types).fetch(i).convertable_to?(type.tuple_types.fetch(i))
311
+ return false
312
+ end
313
+ end
314
+ return true
315
+ else
316
+ return false
317
+ end
318
+ when :csr
319
+ return (type.kind == :csr && type.csr.name == @csr.name) || type.convertable_to?(Type.new(:bits, width:))
320
+ when :bitfield
321
+ if (type.kind == :bitfield && name == type.name)
322
+ return true
323
+ elsif (type.kind == :bits && type.width == @width)
324
+ return true
325
+ else
326
+ # be strict with bitfields -- only accept integrals that are exact width Bit types
327
+ return false
328
+ end
329
+ when :array
330
+ return type.kind == :array && type.sub_type.convertable_to?(sub_type) && type.width == @width
331
+ when :string
332
+ return type.kind == :string
333
+ when :void
334
+ return type.kind == :void
335
+ when :struct
336
+ return type.kind == :struct && (T.cast(type, StructType).name == T.cast(self, StructType).type_name)
337
+ else
338
+ raise "unimplemented type '#{@kind}'"
339
+ end
340
+ end
341
+
342
+ # return IDL representation of the type
343
+ sig { returns(String) }
344
+ def to_idl
345
+ case @kind
346
+ when :bits
347
+ if @width == :unknown
348
+ raise "Cannot generate an IDL type with an unknown width"
349
+ end
350
+ if signed?
351
+ raise "Cannot directly represent a signed bits"
352
+ else
353
+ "Bits<#{@width}"
354
+ end
355
+ when :String
356
+ "String"
357
+ when :boolean
358
+ "Boolean"
359
+ else
360
+ raise "TODO"
361
+ end
362
+ end
363
+
364
+ def to_s
365
+ ((@qualifiers.empty?) ? "" : "#{@qualifiers.map(&:to_s).join(' ')} ") + \
366
+ if @kind == :bits
367
+ "Bits<#{@width}>"
368
+ elsif @kind == :enum
369
+ "enum definition #{@name}"
370
+ elsif @kind == :boolean
371
+ "Boolean"
372
+ elsif @kind == :enum_ref
373
+ "enum #{T.must(@enum_class).name}"
374
+ elsif @kind == :tuple
375
+ "(#{T.must(@tuple_types).map { |t| t.to_s }.join(',')})"
376
+ elsif @kind == :bitfield
377
+ "bitfield #{@name}"
378
+ elsif @kind == :array
379
+ "array of #{@sub_type}"
380
+ elsif @kind == :csr
381
+ "CSR[#{@csr.name}]"
382
+ elsif @kind == :void
383
+ "void"
384
+ elsif @kind == :string
385
+ "string"
386
+ elsif @kind == :struct
387
+ "struct #{T.cast(self, StructType).type_name}"
388
+ elsif @kind == :function
389
+ "function #{name}"
390
+ else
391
+ raise @kind.to_s
392
+ end
393
+ end
394
+ alias fully_qualified_name to_s
395
+
396
+ def name
397
+ if @kind == :bits
398
+ "Bits<#{@width}>"
399
+ elsif @kind == :enum
400
+ @name
401
+ elsif @kind == :bitfield
402
+ @name
403
+ elsif @kind == :function
404
+ @name
405
+ elsif @kind == :csr
406
+ @csr.name
407
+ elsif @kind == :enum_ref
408
+ T.must(@enum_class).name
409
+ else
410
+ raise @kind.to_s
411
+ end
412
+ end
413
+
414
+ def ary?
415
+ @kind == :array
416
+ end
417
+
418
+ def const?
419
+ @qualifiers.include?(:const)
420
+ end
421
+
422
+ def mutable?
423
+ !const?
424
+ end
425
+
426
+ def signed?
427
+ @qualifiers.include?(:signed)
428
+ end
429
+
430
+ def global?
431
+ @qualifiers.include?(:global)
432
+ end
433
+
434
+ def known?
435
+ @qualifiers.include?(:known)
436
+ end
437
+
438
+ def make_signed
439
+ @qualifiers.append(:signed).uniq!
440
+ self
441
+ end
442
+
443
+ # make this Type constant, and return self
444
+ sig { returns(Type) }
445
+ def make_const!
446
+ @qualifiers.append(:const).uniq!
447
+ self
448
+ end
449
+
450
+ # make a clone of this Type, add a constant qualifier, and return the new type
451
+ sig { returns(Type) }
452
+ def make_const
453
+ new_t = clone
454
+ new_t.make_const!
455
+ end
456
+
457
+ def make_global
458
+ @qualifiers.append(:global).uniq!
459
+ self
460
+ end
461
+
462
+ def make_known
463
+ @qualifiers.append(:known).uniq!
464
+ self
465
+ end
466
+
467
+ # @return [Idl::Type] Type of a scalar
468
+ # @param schema [Hash] JSON Schema description of a scalar
469
+ sig { params(schema: T::Hash[String, T.untyped]).returns(T.nilable(Type)) }
470
+ def self.from_json_schema_scalar_type(schema)
471
+ if schema.key?("type")
472
+ case schema["type"]
473
+ when "boolean"
474
+ Type.new(:boolean)
475
+ when "integer"
476
+ if schema.key?("enum")
477
+ Type.new(:bits, width: schema["enum"].max.bit_length)
478
+ elsif schema.key?("maximum")
479
+ Type.new(:bits, width: schema["maximum"].bit_length)
480
+ else
481
+ Type.new(:bits, width: 128)
482
+ end
483
+ when "string"
484
+ if schema.key?("enum")
485
+ Type.new(:string, width: schema["enum"].map(&:length).max)
486
+ else
487
+ Type.new(:string, width: 4096)
488
+ end
489
+ else
490
+ raise "Unhandled JSON schema type"
491
+ end
492
+ elsif schema.key?("const")
493
+ case schema["const"]
494
+ when TrueClass, FalseClass
495
+ Type.new(:boolean)
496
+ when Integer
497
+ Type.new(:bits, width: schema["const"].bit_length)
498
+ when String
499
+ Type.new(:string, width: schema["const"].length)
500
+ else
501
+ raise "Unhandled const type"
502
+ end
503
+ elsif schema.key?("enum")
504
+ raise "Mixed types in enum" unless schema["enum"].all? { |e| e.class == schema["enum"].fetch(0).class }
505
+
506
+ case schema["enum"].fetch(0)
507
+ when TrueClass, FalseClass
508
+ Type.new(:boolean)
509
+ when Integer
510
+ Type.new(:bits, width: schema["enum"].map { |e| e.bit_length }.max)
511
+ when String
512
+ Type.new(:string, width: schema["enum"].map { |e| e.length }.max)
513
+ else
514
+ raise "unhandled enum type"
515
+ end
516
+ elsif schema.key?("allOf")
517
+ subschema_types = schema.fetch("allOf").map { |subschema| from_json_schema_scalar_type(subschema) }.compact
518
+ raise "No subschema has a defined type" if subschema_types.empty?
519
+
520
+ if subschema_types.fetch(0).kind == :string
521
+ raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :string }
522
+
523
+ subschema_types.fetch(0)
524
+ elsif subschema_types.fetch(0).kind == :boolean
525
+ raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :boolean }
526
+
527
+ subschema_types.fetch(0)
528
+ elsif subschema_types.fetch(0).kind == :bits
529
+ raise "Subschema types do not agree" unless subschema_types[1..].all? { |t| t.kind == :bits }
530
+
531
+ unknown_width_type = subschema_types.find { |t| t.width == :unknown }
532
+ return unknown_width_type unless unknown_width_type.nil?
533
+
534
+ subschema_types.max { |t1, t2| t1.width <=> t2.width }
535
+ else
536
+ raise "unhandled subschema type"
537
+ end
538
+ elsif schema.key?("$ref")
539
+ if schema.fetch("$ref") == "schema_defs.json#/$defs/uint32"
540
+ Type.new(:bits, width: 32)
541
+ elsif schema.fetch("$ref") == "schema_defs.json#/$defs/uint64"
542
+ Type.new(:bits, width: 64)
543
+ else
544
+ raise "unhandled ref: #{schema.fetch("$ref")}"
545
+ end
546
+ elsif schema.key?("not")
547
+ nil
548
+ else
549
+ raise "unhandled scalar schema:\n#{schema}"
550
+ end
551
+ end
552
+ private_class_method :from_json_schema_scalar_type
553
+
554
+ # @return [Idl::Type] Type of array
555
+ # @param schema [Hash] JSON Schema description of an array
556
+ sig { params(schema: T::Hash[String, T.untyped]).returns(Type) }
557
+ def self.from_json_schema_array_type(schema)
558
+ width = schema["minItems"]
559
+ if !schema.key?("minItems") || !schema.key?("maxItems") || (schema["minItems"] != schema["maxItems"])
560
+ width = :unknown
561
+ end
562
+
563
+ if schema["items"].is_a?(Hash)
564
+ Type.new(:array, width:, sub_type: from_json_schema(schema["items"]))
565
+ else
566
+ raise "unexpected #{schema}" unless schema["items"].is_a?(Array)
567
+
568
+ # this ia an array with each element specified
569
+ sub_type = T.let(nil, T.nilable(Type))
570
+ schema["items"].each do |item_schema|
571
+ if sub_type.nil?
572
+ sub_type = from_json_schema_scalar_type(item_schema)
573
+ else
574
+ unless sub_type.equal_to?(from_json_schema_scalar_type(item_schema))
575
+ raise "Schema error: Array elements must be the same type (#{sub_type} #{from_json_schema_scalar_type(item_schema)}) \n#{schema["items"]}"
576
+ end
577
+ end
578
+ end
579
+ if schema.key?("additionalItems")
580
+ if sub_type.nil?
581
+ sub_type = from_json_schema_scalar_type(schema["additionalItems"])
582
+ else
583
+ unless sub_type.equal_to?(from_json_schema_scalar_type(schema["additionalItems"]))
584
+ raise "Schema error: Array elements must be the same type"
585
+ end
586
+ end
587
+ end
588
+ Type.new(:array, width:, sub_type:)
589
+ end
590
+ end
591
+ private_class_method :from_json_schema_array_type
592
+
593
+ # @returns [Idl::Type] Type described by JSON +schema+
594
+ sig { params(schema: T::Hash[String, T.untyped]).returns(T.nilable(Type)) }
595
+ def self.from_json_schema(schema)
596
+ hsh = schema.to_h
597
+ if hsh.key?("type")
598
+ case hsh["type"]
599
+ when "boolean", "integer", "string"
600
+ from_json_schema_scalar_type(hsh)
601
+ when "array"
602
+ from_json_schema_array_type(hsh)
603
+ else
604
+ raise "unexpected"
605
+ end
606
+ else
607
+ from_json_schema_scalar_type(hsh)
608
+ end
609
+ end
610
+ end
611
+
612
+ class StructType < Type
613
+ sig { returns(String) }
614
+ attr_reader :type_name
615
+
616
+ sig { params(type_name: String, member_types: T::Array[Type], member_names: T::Array[String]).void }
617
+ def initialize(type_name, member_types, member_names)
618
+ super(:struct)
619
+ @type_name = type_name
620
+ @member_types = member_types
621
+ @member_names = member_names
622
+ end
623
+
624
+ sig { returns(String) }
625
+ def name = @type_name
626
+
627
+ def clone
628
+ StructType.new(@type_name, @member_types, @member_names)
629
+ end
630
+
631
+ def default
632
+ hsh = {}
633
+ @member_types.size.times do |i|
634
+ hsh[@member_names.fetch(i)] = @member_types.fetch(i).default
635
+ end
636
+ hsh
637
+ end
638
+
639
+ def member?(name) = @member_names.include?(name)
640
+
641
+ def member_type(member_name)
642
+ idx = @member_names.index(member_name)
643
+ raise "No member named '#{member_name}'" if idx.nil?
644
+
645
+ @member_types[idx]
646
+ end
647
+
648
+ # does this struct have any members whose type depends on a runtime parameter?
649
+ def runtime?
650
+ @member_types.any?(&:runtime?)
651
+ end
652
+ end
653
+
654
+ class EnumerationType < Type
655
+ extend T::Sig
656
+
657
+ # @return [Integer] The bit width of the enumeration elements
658
+ sig { returns(Integer) }
659
+ def width = T.cast(@width, Integer)
660
+
661
+ # @return [Array<String>] The names of the enumeration elements, in the same order as element_values
662
+ sig { returns(T::Array[String]) }
663
+ attr_reader :element_names
664
+
665
+ # @return [Array<Integer>] The values of the enumeration elements, in the same order as element_names
666
+ sig { returns(T::Array[Integer]) }
667
+ attr_reader :element_values
668
+
669
+ # @return [Type] The type of an reference to this Enumeration class
670
+ sig { returns(Type) }
671
+ attr_reader :ref_type
672
+
673
+ # @param type_name [String] The name of the enum class
674
+ # @param element_names [Array<String>] The names of the elements, in the same order as +element_values+
675
+ # @param element_values [Array<Integer>] The values of the elements, in the same order as +element_names+
676
+ sig {
677
+ params(
678
+ type_name: String,
679
+ element_names: T::Array[String],
680
+ element_values: T::Array[Integer],
681
+ builtin: T::Boolean
682
+ ).void
683
+ }
684
+ def initialize(type_name, element_names, element_values, builtin: false)
685
+ width = T.must(element_values.max).bit_length
686
+ width = 1 if width.zero? # can happen if only enum member has value 0
687
+ super(:enum, width:)
688
+
689
+ @name = type_name.freeze
690
+ @element_names = element_names.freeze
691
+ @element_values = element_values.freeze
692
+ raise "names and values aren't the same size" unless element_names.size == element_values.size
693
+
694
+ @ref_type = Type.new(:enum_ref, enum_class: self).freeze
695
+ @builtin = builtin.freeze
696
+ end
697
+
698
+ sig { returns(T::Boolean) }
699
+ def builtin? = @builtin
700
+
701
+ sig { returns(EnumerationType) }
702
+ def clone
703
+ EnumerationType.new(T.must(@name), @element_names, @element_values)
704
+ end
705
+
706
+ sig { params(element_name: String).returns(T.nilable(Integer)) }
707
+ def value(element_name)
708
+ i = @element_names.index(element_name)
709
+ return nil if i.nil?
710
+
711
+ @element_values[i]
712
+ end
713
+
714
+ sig { params(element_value: Integer).returns(T.nilable(String)) }
715
+ def element_name(element_value)
716
+ i = @element_values.index(element_value)
717
+ raise "? #{element_value}" if i.nil?
718
+ return nil if i.nil?
719
+
720
+ @element_names[i]
721
+ end
722
+ end
723
+
724
+ class BitfieldType < Type
725
+ def width = @field_ranges.map(&:size).reduce(&:+)
726
+ def initialize(type_name, width, field_names, field_ranges)
727
+ super(:bitfield, name: type_name, width:)
728
+
729
+ @field_names = field_names
730
+ @field_ranges = field_ranges
731
+ raise "unexpected" unless field_names.is_a?(Array)
732
+ raise "unexpected" unless field_ranges.is_a?(Array) && field_names.length == field_ranges.length
733
+ end
734
+
735
+ def range(field_name)
736
+ i = @field_names.index(field_name)
737
+ raise "Could not find #{field_name} in #{@name}" if i.nil?
738
+
739
+ @field_ranges[i]
740
+ end
741
+
742
+ def field_names
743
+ @field_names
744
+ end
745
+
746
+ def clone
747
+ BitfieldType.new(
748
+ name,
749
+ width,
750
+ field_names,
751
+ @field_ranges
752
+ )
753
+ end
754
+
755
+ end
756
+
757
+ # represents a CSR register
758
+ class CsrType < Type
759
+ extend T::Sig
760
+
761
+ sig { returns(Csr) }
762
+ attr_reader :csr
763
+
764
+ sig { params(csr: Csr, qualifiers: T::Array[Symbol]).void }
765
+ def initialize(csr, qualifiers: [])
766
+ super(:csr, name: csr.name, csr: csr, width: csr.max_length, qualifiers: qualifiers)
767
+ end
768
+
769
+ sig { returns(T::Array[CsrField]) }
770
+ def fields
771
+ raise "fields are unknown" if @csr == :unknown
772
+
773
+ @csr.fields
774
+ end
775
+ end
776
+
777
+ class FunctionType < Type
778
+ attr_reader :func_def_ast
779
+
780
+ sig {
781
+ params(
782
+ func_name: String,
783
+ func_def_ast: FunctionDefAst,
784
+ symtab: SymbolTable
785
+ )
786
+ .void
787
+ }
788
+ def initialize(func_name, func_def_ast, symtab)
789
+ super(:function, name: func_name)
790
+ @func_def_ast = func_def_ast
791
+ @symtab = symtab
792
+
793
+ raise "symtab should be at level 1" unless symtab.levels == 1
794
+ end
795
+
796
+ def argument_nodes = @func_def_ast.argument_nodes
797
+
798
+ sig {
799
+ returns(FunctionType)
800
+ }
801
+ def clone
802
+ FunctionType.new(name, @func_def_ast, @symtab)
803
+ end
804
+
805
+ sig { returns(T::Boolean) }
806
+ def builtin? = @func_def_ast.builtin?
807
+
808
+ sig { returns(T::Boolean) }
809
+ def generated? = @func_def_ast.generated?
810
+
811
+ sig { returns(T::Boolean) }
812
+ def external? = @func_def_ast.external?
813
+
814
+ sig { returns(Integer) }
815
+ def num_args = @func_def_ast.num_args
816
+
817
+ # apply the arguments as Vars.
818
+ # then add the value to the Var
819
+ sig {
820
+ params(
821
+ symtab: SymbolTable, # global symbol table
822
+ argument_nodes: T::Array[Rvalue], # arguments
823
+ call_site_symtab: SymbolTable, # symbol table at the function call site
824
+ func_call_ast: FunctionCallExpressionAst
825
+ ).returns(T::Array[T.any(Integer, Symbol)])
826
+ }
827
+ def apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast)
828
+ idx = 0
829
+ values = []
830
+ @func_def_ast.arguments(symtab).each do |atype, aname|
831
+ func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size
832
+ value_result = Idl::AstNode.value_try do
833
+ value = argument_nodes.fetch(idx).value(call_site_symtab)
834
+ symtab.add(aname, Var.new(aname, atype, value))
835
+ values << value
836
+ end
837
+ Idl::AstNode.value_else(value_result) do
838
+ symtab.add(aname, Var.new(aname, atype))
839
+ values << :unknown
840
+ end
841
+ idx += 1
842
+ end
843
+ values
844
+ end
845
+
846
+ # @return [Array<Integer,Boolean>] Array of argument values, if known
847
+ # @return [nil] if at least one argument value is not known
848
+ sig {
849
+ params(
850
+ symtab: SymbolTable, # global symbol table
851
+ argument_nodes: T::Array[Rvalue], # arguments
852
+ call_site_symtab: SymbolTable, # symbol table at the function call site
853
+ func_call_ast: FunctionCallExpressionAst
854
+ ).returns(T.nilable(T::Array[T.any(Integer, T::Boolean, Symbol)]))
855
+ }
856
+ def argument_values(symtab, argument_nodes, call_site_symtab, func_call_ast)
857
+ idx = 0
858
+ values = []
859
+ @func_def_ast.arguments(symtab).each do |atype, aname|
860
+ func_call_ast.type_error "Missing argument #{idx}" if idx >= argument_nodes.size
861
+ value_result = Idl::AstNode.value_try do
862
+ values << argument_nodes.fetch(idx).value(call_site_symtab)
863
+ end
864
+ Idl::AstNode.value_else(value_result) do
865
+ return nil
866
+ end
867
+ idx += 1
868
+ end
869
+ values
870
+ end
871
+
872
+ # @param func_call_ast [FunctionCallExpressionAst] The function call interested in the return type
873
+ # return [Type] type of the call return
874
+ sig {
875
+ params(
876
+ argument_nodes: T::Array[Rvalue],
877
+ func_call_ast: FunctionCallExpressionAst
878
+ ).returns(Type)
879
+ }
880
+ def return_type(argument_nodes, func_call_ast)
881
+ rtype =
882
+ begin
883
+ symtab = @symtab.global_clone
884
+ symtab.push(func_call_ast)
885
+ @func_def_ast.return_type(symtab)
886
+ ensure
887
+ symtab.pop
888
+ symtab.release
889
+ end
890
+
891
+ T.must(rtype)
892
+ end
893
+
894
+ sig {
895
+ params(
896
+ argument_nodes: T::Array[Rvalue], # arguments
897
+ call_site_symtab: SymbolTable, # symbol table at the function call site
898
+ func_call_ast: FunctionCallExpressionAst
899
+ ).returns(T.nilable(T.any(Integer, T::Boolean, Symbol, T::Hash[String, T.untyped])))
900
+ }
901
+ def return_value(argument_nodes, call_site_symtab, func_call_ast)
902
+ symtab = @symtab.global_clone
903
+ symtab.push(func_call_ast)
904
+ apply_arguments(symtab, argument_nodes, call_site_symtab, func_call_ast)
905
+
906
+ begin
907
+ value = @func_def_ast.body.return_value(symtab)
908
+ ensure
909
+ symtab.pop
910
+ symtab.release
911
+ end
912
+ raise "?" if value.is_a?(SymbolTable)
913
+ value
914
+ end
915
+
916
+ sig {
917
+ params(
918
+ index: Integer,
919
+ argument_nodes: T::Array[Rvalue], # arguments
920
+ call_site_symtab: SymbolTable, # symbol table at the function call site
921
+ func_call_ast: FunctionCallExpressionAst
922
+ ).returns(T.nilable(Type))
923
+ }
924
+ def argument_type(index, argument_nodes, call_site_symtab, func_call_ast)
925
+ return nil if index >= @func_def_ast.num_args
926
+
927
+ symtab = @symtab.global_clone
928
+ symtab.push(func_call_ast)
929
+
930
+ begin
931
+ arguments = @func_def_ast.arguments(symtab)
932
+ ensure
933
+ symtab.pop
934
+ symtab.release
935
+ end
936
+ arguments[index][0]
937
+ end
938
+
939
+ sig {
940
+ params(
941
+ index: Integer,
942
+ func_call_ast: FunctionCallExpressionAst
943
+ ).returns(T.nilable(String))
944
+ }
945
+ def argument_name(index, func_call_ast)
946
+ return nil if index >= @func_def_ast.num_args
947
+
948
+ symtab = @symtab.global_clone
949
+ symtab.push(func_call_ast)
950
+
951
+ begin
952
+ arguments = @func_def_ast.arguments(symtab)
953
+ ensure
954
+ symtab.pop
955
+ symtab.release
956
+ end
957
+ arguments[index][1]
958
+ end
959
+
960
+ sig {
961
+ returns(FunctionBodyAst)
962
+ }
963
+ def body = @func_def_ast.body
964
+ end
965
+
966
+ # XReg is really a Bits<> type, so we override it just to get
967
+ # prettier prints
968
+ class XregType < Type
969
+ def initialize(xlen)
970
+ super(:bits, width: xlen, max_width: 64)
971
+ end
972
+
973
+ def to_s
974
+ "XReg"
975
+ end
976
+
977
+ def to_cxx
978
+ "XReg"
979
+ end
980
+ end
981
+
982
+ # pre-define some common types
983
+ Bits1Type = Type.new(:bits, width: 1).freeze
984
+ Bits32Type = Type.new(:bits, width: 32).freeze
985
+ Bits64Type = Type.new(:bits, width: 64).freeze
986
+ BitsUnknownType = Type.new(:bits, width: :unknown).freeze
987
+ ConstBitsUnknownType = Type.new(:bits, width: :unknown, qualifiers: [:const]).freeze
988
+ ConstBoolType = Type.new(:boolean, qualifiers: [:const]).freeze
989
+ BoolType = Type.new(:boolean).freeze
990
+ VoidType = Type.new(:void).freeze
991
+ StringType = Type.new(:string).freeze
992
+ end