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.
- checksums.yaml +7 -0
- data/LICENSE +26 -0
- data/bin/idlc +10 -0
- data/lib/idlc/ast.rb +9611 -0
- data/lib/idlc/ast_decl.rb +22 -0
- data/lib/idlc/cli.rb +232 -0
- data/lib/idlc/idl.treetop +675 -0
- data/lib/idlc/idl_parser.rb +15386 -0
- data/lib/idlc/interfaces.rb +135 -0
- data/lib/idlc/log.rb +23 -0
- data/lib/idlc/passes/find_referenced_csrs.rb +39 -0
- data/lib/idlc/passes/find_return_values.rb +76 -0
- data/lib/idlc/passes/find_src_registers.rb +125 -0
- data/lib/idlc/passes/gen_adoc.rb +355 -0
- data/lib/idlc/passes/gen_option_adoc.rb +169 -0
- data/lib/idlc/passes/prune.rb +957 -0
- data/lib/idlc/passes/reachable_exceptions.rb +206 -0
- data/lib/idlc/passes/reachable_functions.rb +221 -0
- data/lib/idlc/symbol_table.rb +549 -0
- data/lib/idlc/syntax_node.rb +64 -0
- data/lib/idlc/type.rb +992 -0
- data/lib/idlc/version.rb +10 -0
- data/lib/idlc.rb +409 -0
- metadata +394 -0
|
@@ -0,0 +1,957 @@
|
|
|
1
|
+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
|
2
|
+
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
3
|
+
|
|
4
|
+
# typed: false
|
|
5
|
+
# frozen_string_literal: true
|
|
6
|
+
|
|
7
|
+
# This file contains AST functions that prune out unreachable paths given
|
|
8
|
+
# some known values in a symbol table
|
|
9
|
+
# It adds a `prune` function to every AstNode that returns a new,
|
|
10
|
+
# pruned subtree.
|
|
11
|
+
|
|
12
|
+
require "sorbet-runtime"
|
|
13
|
+
|
|
14
|
+
require_relative "../ast"
|
|
15
|
+
|
|
16
|
+
module Idl
|
|
17
|
+
module PruneHelpers
|
|
18
|
+
extend T::Sig
|
|
19
|
+
def self.create_int_literal(value, forced_type: nil)
|
|
20
|
+
width = forced_type ? forced_type.width : value.bit_length
|
|
21
|
+
raise "pruning error: attempting to prune an integer with unknown width" unless width.is_a?(Integer)
|
|
22
|
+
width = 1 if width == 0
|
|
23
|
+
v = value <= 512 ? value.to_s : "h#{value.to_s(16)}"
|
|
24
|
+
str = "#{width}'#{v}"
|
|
25
|
+
Idl::IntLiteralAst.new(str, 0...str.size, str)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.create_bool_literal(value)
|
|
29
|
+
if value
|
|
30
|
+
Idl::TrueExpressionAst.new("true", 0..4)
|
|
31
|
+
else
|
|
32
|
+
Idl::FalseExpressionAst.new("false", 0..5)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# returns nil if array holds bools
|
|
37
|
+
# otherwise (it holds bits), returns max bitwidth of all elements
|
|
38
|
+
sig { params(symtab: Idl::SymbolTable, node: Idl::AstNode, max: T.nilable(Integer)).returns(T.nilable(Integer)) }
|
|
39
|
+
def self.find_max_element_width(symtab, node, max = nil)
|
|
40
|
+
if node.is_a?(Idl::ArrayLiteralAst)
|
|
41
|
+
node.entries.map do |e|
|
|
42
|
+
e_max = find_max_element_width(symtab, e)
|
|
43
|
+
max.nil? ? e_max : [max, e_max].max
|
|
44
|
+
end.max
|
|
45
|
+
else
|
|
46
|
+
if node.is_a?(Idl::TrueExpressionAst) || node.is_a?(Idl::FalseExpressionAst)
|
|
47
|
+
nil
|
|
48
|
+
else
|
|
49
|
+
node_width = node.type(symtab).width
|
|
50
|
+
max.nil? ? node_width : [max, node_width].max
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.coerce_ary_element_widths(symtab, elements, max_element_width)
|
|
56
|
+
if elements.is_a?(Array) && elements.empty?
|
|
57
|
+
Idl::ArrayLiteralAst.new("pruned_literal_ary", 0..18, [])
|
|
58
|
+
elsif elements.fetch(0).is_a?(Idl::ArrayLiteralAst)
|
|
59
|
+
# Recursively coerce nested arrays - pass e.entries, not e
|
|
60
|
+
Idl::ArrayLiteralAst.new("pruned_literal_ary", 0..18,
|
|
61
|
+
elements.map { |e| coerce_ary_element_widths(symtab, e.entries, max_element_width) })
|
|
62
|
+
else
|
|
63
|
+
# Base case: elements is an array of leaf nodes, coerce each to max_element_width
|
|
64
|
+
coerced = elements.map { |node| create_int_literal(node.value(symtab), forced_type: Idl::Type.new(:bits, width: max_element_width)) }
|
|
65
|
+
Idl::ArrayLiteralAst.new("pruned_literal_ary", 0..18, coerced)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def self.create_literal(symtab, value, type, forced_type: nil)
|
|
70
|
+
case type.kind
|
|
71
|
+
when :enum_ref
|
|
72
|
+
member_name = type.enum_class.element_names[type.enum_class.element_values.index(value)]
|
|
73
|
+
str = "#{type.enum_class.name}::#{member_name}"
|
|
74
|
+
Idl::EnumRefAst.new(str, 0...str.size, type.enum_class.name, member_name)
|
|
75
|
+
when :bits
|
|
76
|
+
create_int_literal(value, forced_type:)
|
|
77
|
+
when :boolean
|
|
78
|
+
create_bool_literal(value)
|
|
79
|
+
when :array
|
|
80
|
+
elements = value.map { |e| create_literal(symtab, e, type.sub_type) }
|
|
81
|
+
# array elements MUST have the same type, so we need to coerce them
|
|
82
|
+
# find the leaf level, and get the bit widths if needed
|
|
83
|
+
ary = Idl::ArrayLiteralAst.new("pruned_literal_ary", 0..18, elements)
|
|
84
|
+
max_element_width = find_max_element_width(symtab, ary)
|
|
85
|
+
if max_element_width.nil?
|
|
86
|
+
ary
|
|
87
|
+
else
|
|
88
|
+
coerce_ary_element_widths(symtab, elements, max_element_width)
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
raise "TODO: #{type}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
module Idl
|
|
98
|
+
# set up a default
|
|
99
|
+
class AstNode
|
|
100
|
+
# forced_type, when not nil, is the type that the pruned result must be
|
|
101
|
+
# if is used when pruning expressions to ensure that the prune doesn't change
|
|
102
|
+
# bit width just because a value is known and would fit in something smaller
|
|
103
|
+
def prune(symtab, forced_type: nil)
|
|
104
|
+
new_children = children.map { |child| child.prune(symtab, forced_type:) }
|
|
105
|
+
|
|
106
|
+
new_node = dup
|
|
107
|
+
new_node.instance_variable_set(:@children, new_children)
|
|
108
|
+
|
|
109
|
+
if is_a?(Executable)
|
|
110
|
+
value_try do
|
|
111
|
+
execute(symtab)
|
|
112
|
+
end
|
|
113
|
+
# value_else: execute raised ValueError; symtab state is already correct
|
|
114
|
+
end
|
|
115
|
+
add_symbol(symtab) if is_a?(Declaration)
|
|
116
|
+
|
|
117
|
+
new_node
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def nullify_assignments(symtab)
|
|
121
|
+
children.each { |child| child.nullify_assignments(symtab) }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
class VariableAssignmentAst < AstNode
|
|
125
|
+
def prune(symtab, forced_type: nil)
|
|
126
|
+
new_ast = VariableAssignmentAst.new(input, interval, lhs.dup, rhs.prune(symtab))
|
|
127
|
+
value_try do
|
|
128
|
+
new_ast.execute(symtab)
|
|
129
|
+
end
|
|
130
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
131
|
+
new_ast
|
|
132
|
+
end
|
|
133
|
+
def nullify_assignments(symtab)
|
|
134
|
+
sym = symtab.get(lhs.text_value)
|
|
135
|
+
unless sym.nil?
|
|
136
|
+
sym.value = nil
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
class AryElementAssignmentAst < AstNode
|
|
141
|
+
def nullify_assignments(symtab)
|
|
142
|
+
case lhs.type(symtab).kind
|
|
143
|
+
when :array
|
|
144
|
+
value_result = value_try do
|
|
145
|
+
lhs_value = lhs.value(symtab)
|
|
146
|
+
value_result2 = value_try do
|
|
147
|
+
lhs_value[idx.value(symtab)] = nil
|
|
148
|
+
end
|
|
149
|
+
value_else(value_result2) do
|
|
150
|
+
# index unknown: nullify entire array
|
|
151
|
+
lhs_value.map! { |_v| nil }
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
value_else(value_result) do
|
|
155
|
+
# array var itself is unknown; nothing more to do
|
|
156
|
+
end
|
|
157
|
+
when :bits
|
|
158
|
+
var = symtab.get(lhs.text_value)
|
|
159
|
+
var.value = nil unless var.nil?
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
class AryRangeAssignmentAst < AstNode
|
|
164
|
+
def nullify_assignments(symtab)
|
|
165
|
+
return if variable.type(symtab).global?
|
|
166
|
+
var = symtab.get(variable.name)
|
|
167
|
+
var.value = nil unless var.nil?
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
class FieldAssignmentAst < AstNode
|
|
171
|
+
def nullify_assignments(symtab)
|
|
172
|
+
var = symtab.get(id.name)
|
|
173
|
+
var.value = nil unless var.nil?
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
class MultiVariableAssignmentAst < AstNode
|
|
177
|
+
def nullify_assignments(symtab)
|
|
178
|
+
variables.each do |v|
|
|
179
|
+
sym = symtab.get(v.text_value)
|
|
180
|
+
sym.value = nil unless sym.nil?
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
class PostIncrementExpressionAst < AstNode
|
|
185
|
+
def nullify_assignments(symtab)
|
|
186
|
+
var = symtab.get(rval.text_value)
|
|
187
|
+
var.value = nil unless var.nil?
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
class PostDecrementExpressionAst < AstNode
|
|
191
|
+
def nullify_assignments(symtab)
|
|
192
|
+
var = symtab.get(rval.text_value)
|
|
193
|
+
var.value = nil unless var.nil?
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
class FunctionCallExpressionAst < AstNode
|
|
197
|
+
def prune(symtab, forced_type: nil)
|
|
198
|
+
value_result = value_try do
|
|
199
|
+
v = value(symtab)
|
|
200
|
+
if type(symtab).kind == :bits
|
|
201
|
+
# can only prune if the bit width of the integer is known
|
|
202
|
+
if type(symtab).width == :unknown
|
|
203
|
+
value_error "Unknown width"
|
|
204
|
+
end
|
|
205
|
+
elsif type(symtab).kind == :struct
|
|
206
|
+
value_error <<~MSG
|
|
207
|
+
Literal struct values can't be pruned since a struct can't be initialized with a single expression.
|
|
208
|
+
This would require syntax like { .a = FOO, .b = BAR }
|
|
209
|
+
MSG
|
|
210
|
+
end
|
|
211
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
212
|
+
end
|
|
213
|
+
value_else(value_result) do
|
|
214
|
+
FunctionCallExpressionAst.new(input, interval, name, @children.map { |a| a.prune(symtab) })
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
class VariableDeclarationWithInitializationAst < AstNode
|
|
219
|
+
def prune(symtab, forced_type: nil)
|
|
220
|
+
add_symbol(symtab)
|
|
221
|
+
|
|
222
|
+
# do we want to remove a constant? If so, need to add a prune for IdAst that
|
|
223
|
+
# spits out a literal
|
|
224
|
+
#
|
|
225
|
+
# if lhs.const?
|
|
226
|
+
# value_try do
|
|
227
|
+
# rhs.value(symtab)
|
|
228
|
+
# # rhs value is known, and variable is const. it can be removed
|
|
229
|
+
# return NoopAst.new
|
|
230
|
+
# end
|
|
231
|
+
# end
|
|
232
|
+
|
|
233
|
+
VariableDeclarationWithInitializationAst.new(
|
|
234
|
+
input, interval,
|
|
235
|
+
type_name.dup,
|
|
236
|
+
lhs.dup,
|
|
237
|
+
ary_size&.prune(symtab),
|
|
238
|
+
rhs.prune(symtab),
|
|
239
|
+
@for_iter_var
|
|
240
|
+
)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
class ForLoopAst < AstNode
|
|
244
|
+
def prune(symtab, forced_type: nil)
|
|
245
|
+
symtab.push(self)
|
|
246
|
+
symtab.add(init.lhs.name, Var.new(init.lhs.name, init.lhs_type(symtab)))
|
|
247
|
+
|
|
248
|
+
# Nullify any outer-scope variable assigned in the loop body, since we
|
|
249
|
+
# don't know how many iterations ran (or if any ran at all)
|
|
250
|
+
stmts.each { |stmt| stmt.nullify_assignments(symtab) }
|
|
251
|
+
|
|
252
|
+
# Snapshot after nullification so restore brings back nil values, not pre-loop values
|
|
253
|
+
snapshot = symtab.snapshot_values
|
|
254
|
+
|
|
255
|
+
begin
|
|
256
|
+
new_loop =
|
|
257
|
+
ForLoopAst.new(
|
|
258
|
+
input, interval,
|
|
259
|
+
init.prune(symtab),
|
|
260
|
+
condition.prune(symtab),
|
|
261
|
+
update.prune(symtab),
|
|
262
|
+
stmts.map { |s| s.prune(symtab) }
|
|
263
|
+
)
|
|
264
|
+
ensure
|
|
265
|
+
symtab.restore_values(snapshot)
|
|
266
|
+
symtab.pop
|
|
267
|
+
end
|
|
268
|
+
new_loop
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
class FunctionDefAst < AstNode
|
|
272
|
+
def prune(symtab, forced_type: nil)
|
|
273
|
+
pruned_body =
|
|
274
|
+
unless builtin? || generated?
|
|
275
|
+
apply_arg_syms(symtab)
|
|
276
|
+
@body.prune(symtab, args_already_applied: true)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
FunctionDefAst.new(
|
|
280
|
+
input, interval,
|
|
281
|
+
name,
|
|
282
|
+
@return_type_nodes.map(&:dup),
|
|
283
|
+
@argument_nodes.map(&:dup),
|
|
284
|
+
@desc,
|
|
285
|
+
@type,
|
|
286
|
+
pruned_body
|
|
287
|
+
)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
class ParenExpressionAst
|
|
291
|
+
def prune(symtab, forced_type: nil)
|
|
292
|
+
e = expression.prune(symtab, forced_type:)
|
|
293
|
+
if e.is_a?(ParenExpressionAst)
|
|
294
|
+
e
|
|
295
|
+
elsif e.is_a?(IntLiteralAst) || e.is_a?(TrueExpressionAst) || e.is_a?(FalseExpressionAst) || e.is_a?(IdAst)
|
|
296
|
+
e
|
|
297
|
+
else
|
|
298
|
+
ParenExpressionAst.new(input, interval, e)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
class FunctionBodyAst < AstNode
|
|
303
|
+
def prune(symtab, forced_type: nil, args_already_applied: false)
|
|
304
|
+
symtab.push(self)
|
|
305
|
+
|
|
306
|
+
begin
|
|
307
|
+
func_def = find_ancestor(FunctionDefAst)
|
|
308
|
+
unless args_already_applied || func_def.nil?
|
|
309
|
+
|
|
310
|
+
# push args
|
|
311
|
+
func_def.arguments(symtab).each do |arg_type, arg_name|
|
|
312
|
+
symtab.add(arg_name, Var.new(arg_name, arg_type))
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
pruned_body = nil
|
|
317
|
+
|
|
318
|
+
value_result = value_try do
|
|
319
|
+
# go through the statements, and stop if we find one that returns or raises an exception
|
|
320
|
+
statements.each_with_index do |s, idx|
|
|
321
|
+
if s.is_a?(ReturnStatementAst)
|
|
322
|
+
pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) })
|
|
323
|
+
return pruned_body
|
|
324
|
+
elsif s.is_a?(ConditionalReturnStatementAst)
|
|
325
|
+
value_try do
|
|
326
|
+
v = s.return_value(symtab)
|
|
327
|
+
|
|
328
|
+
# conditional return, condition not taken if v.nil?
|
|
329
|
+
unless v.nil?
|
|
330
|
+
pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) })
|
|
331
|
+
return pruned_body
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
# || conditional return, condition not known; keep going
|
|
335
|
+
elsif s.is_a?(StatementAst) && s.action.is_a?(FunctionCallExpressionAst) && s.action.name == "raise"
|
|
336
|
+
pruned_body = FunctionBodyAst.new(input, interval, statements[0..idx].map { |s| s.prune(symtab) })
|
|
337
|
+
return pruned_body
|
|
338
|
+
else
|
|
339
|
+
s.execute(symtab)
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
pruned_body = FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) })
|
|
344
|
+
end
|
|
345
|
+
value_else(value_result) do
|
|
346
|
+
pruned_body = FunctionBodyAst.new(input, interval, statements.map { |s| s.prune(symtab) })
|
|
347
|
+
end
|
|
348
|
+
ensure
|
|
349
|
+
symtab.pop
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
pruned_body
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
class StatementAst < AstNode
|
|
356
|
+
def prune(symtab, forced_type: nil)
|
|
357
|
+
pruned_action = action.prune(symtab)
|
|
358
|
+
|
|
359
|
+
new_stmt = StatementAst.new(input, interval, pruned_action)
|
|
360
|
+
pruned_action.freeze_tree(symtab) unless pruned_action.frozen?
|
|
361
|
+
|
|
362
|
+
pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration)
|
|
363
|
+
# action#prune already handles symtab update (execute)
|
|
364
|
+
|
|
365
|
+
new_stmt
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
class BinaryExpressionAst < AstNode
|
|
369
|
+
# @!macro prune
|
|
370
|
+
def prune(symtab, forced_type: nil)
|
|
371
|
+
value_try do
|
|
372
|
+
val = value(symtab)
|
|
373
|
+
if val.is_a?(Integer)
|
|
374
|
+
# can only prune if the bit width of the integer is known
|
|
375
|
+
if type(symtab).width == :unknown
|
|
376
|
+
value_error "Unknown width"
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
return PruneHelpers.create_literal(symtab, val, type(symtab), forced_type: forced_type || type(symtab))
|
|
380
|
+
end
|
|
381
|
+
# fall through
|
|
382
|
+
|
|
383
|
+
lhs_value = nil
|
|
384
|
+
rhs_value = nil
|
|
385
|
+
|
|
386
|
+
value_try do
|
|
387
|
+
lhs_value = lhs.value(symtab)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
value_try do
|
|
391
|
+
rhs_value = rhs.value(symtab)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
if op == "&&"
|
|
395
|
+
raise "pruning error" unless forced_type.nil? || forced_type.kind == :boolean
|
|
396
|
+
if !lhs_value.nil? && !rhs_value.nil?
|
|
397
|
+
PruneHelpers.create_bool_literal(lhs_value && rhs_value)
|
|
398
|
+
elsif lhs_value == true
|
|
399
|
+
rhs.prune(symtab)
|
|
400
|
+
elsif rhs_value == true
|
|
401
|
+
lhs.prune(symtab)
|
|
402
|
+
elsif lhs_value == false || rhs_value == false
|
|
403
|
+
PruneHelpers.create_bool_literal(false)
|
|
404
|
+
else
|
|
405
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab), @op, rhs.prune(symtab))
|
|
406
|
+
end
|
|
407
|
+
elsif op == "||"
|
|
408
|
+
raise "pruning error" unless forced_type.nil? || forced_type.kind == :boolean
|
|
409
|
+
if !lhs_value.nil? && !rhs_value.nil?
|
|
410
|
+
PruneHelpers.create_bool_literal(lhs_value || rhs_value)
|
|
411
|
+
elsif lhs_value == true || rhs_value == true
|
|
412
|
+
PruneHelpers.create_bool_literal(true)
|
|
413
|
+
elsif lhs_value == false
|
|
414
|
+
rhs.prune(symtab)
|
|
415
|
+
elsif rhs_value == false
|
|
416
|
+
lhs.prune(symtab)
|
|
417
|
+
else
|
|
418
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab), @op, rhs.prune(symtab))
|
|
419
|
+
end
|
|
420
|
+
elsif op == "&"
|
|
421
|
+
if lhs_value == 0 && type(symtab).width != :unknown
|
|
422
|
+
PruneHelpers.create_literal(symtab, 0, forced_type: forced_type || type(symtab))
|
|
423
|
+
elsif (rhs.type(symtab).width != :unknown) && lhs_value == ((1 << rhs.type(symtab).width) - 1) && type(symtab).width != :unknown
|
|
424
|
+
# rhs idenntity
|
|
425
|
+
rhs.prune(symtab, forced_type:)
|
|
426
|
+
elsif rhs_value == 0 && type(symtab).width != :unknown
|
|
427
|
+
# anything & 0 == 0
|
|
428
|
+
PruneHelpers.create_literal(symtab, 0, forced_type: forced_type || type(symtab))
|
|
429
|
+
elsif (lhs.type(symtab).width != :unknown) && rhs_value == ((1 << lhs.type(symtab).width) - 1) && type(symtab).width != :unknown
|
|
430
|
+
# lhs identity
|
|
431
|
+
lhs.prune(symtab, forced_type:)
|
|
432
|
+
else
|
|
433
|
+
# neither lhs nor rhs were prunable
|
|
434
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab, forced_type:), @op, rhs.prune(symtab, forced_type:))
|
|
435
|
+
end
|
|
436
|
+
elsif op == "|"
|
|
437
|
+
rhs_type = rhs.type(symtab)
|
|
438
|
+
lhs_type = lhs.type(symtab)
|
|
439
|
+
|
|
440
|
+
if lhs_value == 0
|
|
441
|
+
# rhs idenntity
|
|
442
|
+
rhs.prune(symtab, forced_type:)
|
|
443
|
+
elsif rhs_type.width != :unknown && lhs_value == ((1 << rhs.type(symtab).width) - 1) && type(symtab).width != :unknown
|
|
444
|
+
# ~0 | anything == ~0
|
|
445
|
+
PruneHelpers.create_literal(symtab, lhs_value, forced_type: forced_type || type(symtab))
|
|
446
|
+
elsif rhs_value == 0 && type(symtab).width != :unknown
|
|
447
|
+
# lhs identity
|
|
448
|
+
lhs.prune(symtab, forced_type:)
|
|
449
|
+
elsif lhs_type.width != :unknown && rhs_value == ((1 << lhs.type(symtab).width) - 1) && type(symtab).width != :unknown
|
|
450
|
+
# anything | ~0 == ~0
|
|
451
|
+
PruneHelpers.create_literal(symtab, rhs_value, forced_type: forced_type || type(symtab))
|
|
452
|
+
else
|
|
453
|
+
# neither lhs nor rhs were prunable
|
|
454
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab, forced_type:), @op, rhs.prune(symtab, forced_type:))
|
|
455
|
+
end
|
|
456
|
+
elsif op == "=="
|
|
457
|
+
if !lhs_value.nil? && !rhs_value.nil?
|
|
458
|
+
PruneHelpers.create_bool_literal(lhs_value == rhs_value)
|
|
459
|
+
else
|
|
460
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab), @op, rhs.prune(symtab))
|
|
461
|
+
end
|
|
462
|
+
else
|
|
463
|
+
BinaryExpressionAst.new(input, interval, lhs.prune(symtab), @op, rhs.prune(symtab))
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
class IfBodyAst < AstNode
|
|
469
|
+
def prune(symtab, restore: true, forced_type: nil)
|
|
470
|
+
pruned_stmts = []
|
|
471
|
+
symtab.push(nil)
|
|
472
|
+
snapshot = symtab.snapshot_values if restore
|
|
473
|
+
stmts.each do |s|
|
|
474
|
+
pruned_stmts << s.prune(symtab)
|
|
475
|
+
|
|
476
|
+
break if pruned_stmts.last.is_a?(StatementAst) && pruned_stmts.last.action.is_a?(FunctionCallExpressionAst) && pruned_stmts.last.action.name == "raise"
|
|
477
|
+
end
|
|
478
|
+
if restore
|
|
479
|
+
symtab.restore_values(snapshot)
|
|
480
|
+
end
|
|
481
|
+
symtab.pop
|
|
482
|
+
IfBodyAst.new(input, interval, pruned_stmts)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
class ElseIfAst < AstNode
|
|
487
|
+
def prune(symtab, forced_type: nil)
|
|
488
|
+
ElseIfAst.new(
|
|
489
|
+
input, interval,
|
|
490
|
+
body.interval,
|
|
491
|
+
cond.prune(symtab),
|
|
492
|
+
body.prune(symtab).stmts
|
|
493
|
+
)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
class IfAst < AstNode
|
|
498
|
+
# @!macro prune
|
|
499
|
+
def prune(symtab, forced_type: nil)
|
|
500
|
+
value_result = value_try do
|
|
501
|
+
if if_cond.value(symtab)
|
|
502
|
+
return if_body.prune(symtab, restore: false)
|
|
503
|
+
elsif !elseifs.empty?
|
|
504
|
+
# we know that the if condition is false, so now we treat the else if
|
|
505
|
+
# as the starting point and try again
|
|
506
|
+
return IfAst.new(
|
|
507
|
+
input, interval,
|
|
508
|
+
elseifs[0].cond.dup,
|
|
509
|
+
elseifs[0].body.dup,
|
|
510
|
+
elseifs[1..].map(&:dup),
|
|
511
|
+
final_else_body.dup).prune(symtab)
|
|
512
|
+
elsif !final_else_body.stmts.empty?
|
|
513
|
+
# the if is false, and there are no else ifs, so the result of the prune is just the pruned else body
|
|
514
|
+
return final_else_body.prune(symtab, restore: false)
|
|
515
|
+
else
|
|
516
|
+
# the if is false, and there are no else ifs or elses. This is just a no-op
|
|
517
|
+
return NoopAst.new
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
value_else(value_result) do
|
|
521
|
+
# we don't know the value of the if condition
|
|
522
|
+
# we still might know the value of an else if
|
|
523
|
+
unknown_elsifs = []
|
|
524
|
+
elseifs.each do |eif|
|
|
525
|
+
value_result = value_try do
|
|
526
|
+
if eif.cond.value(symtab)
|
|
527
|
+
# this elseif is true, so turn it into an else and then we are done
|
|
528
|
+
return IfAst.new(
|
|
529
|
+
input, interval,
|
|
530
|
+
if_cond.dup,
|
|
531
|
+
if_body.dup,
|
|
532
|
+
unknown_elsifs.map(&:dup),
|
|
533
|
+
eif.body.dup
|
|
534
|
+
).prune(symtab)
|
|
535
|
+
else
|
|
536
|
+
# this elseif is false, so we can remove it
|
|
537
|
+
next :ok
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
value_else(value_result) do
|
|
541
|
+
unknown_elsifs << eif
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
# we get here, then we don't know the value of anything. just return this if with everything pruned
|
|
545
|
+
result = IfAst.new(
|
|
546
|
+
input, interval,
|
|
547
|
+
if_cond.prune(symtab),
|
|
548
|
+
if_body.prune(symtab),
|
|
549
|
+
unknown_elsifs.map { |eif| eif.prune(symtab) },
|
|
550
|
+
final_else_body.prune(symtab)
|
|
551
|
+
)
|
|
552
|
+
# Nullify any variable assigned in any branch, since we don't know which ran
|
|
553
|
+
if_body.nullify_assignments(symtab)
|
|
554
|
+
unknown_elsifs.each { |eif| eif.body.nullify_assignments(symtab) }
|
|
555
|
+
final_else_body.nullify_assignments(symtab)
|
|
556
|
+
result
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
class ConditionalReturnStatementAst < AstNode
|
|
562
|
+
def prune(symtab, forced_type: nil)
|
|
563
|
+
value_result = value_try do
|
|
564
|
+
if condition.value(symtab)
|
|
565
|
+
return return_expression.prune(symtab)
|
|
566
|
+
else
|
|
567
|
+
return NoopAst.new
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
value_else(value_result) do
|
|
571
|
+
ConditionalReturnStatementAst.new(input, interval, return_expression.prune(symtab), condition.prune(symtab))
|
|
572
|
+
end
|
|
573
|
+
end
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
class ConditionalStatementAst < AstNode
|
|
577
|
+
def prune(symtab, forced_type: nil)
|
|
578
|
+
value_result = value_try do
|
|
579
|
+
if condition.value(symtab)
|
|
580
|
+
pruned_action = action.prune(symtab)
|
|
581
|
+
pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration)
|
|
582
|
+
value_result = value_try do
|
|
583
|
+
pruned_action.execute(symtab) if pruned_action.is_a?(Executable)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
return StatementAst.new(input, interval, pruned_action)
|
|
587
|
+
else
|
|
588
|
+
return NoopAst.new
|
|
589
|
+
end
|
|
590
|
+
end
|
|
591
|
+
value_else(value_result) do
|
|
592
|
+
# condition not known
|
|
593
|
+
pruned_action = action.prune(symtab)
|
|
594
|
+
pruned_action.add_symbol(symtab) if pruned_action.is_a?(Declaration)
|
|
595
|
+
value_result = value_try do
|
|
596
|
+
pruned_action.execute(symtab) if pruned_action.is_a?(Executable)
|
|
597
|
+
end
|
|
598
|
+
# Condition is unknown, so the assignment may not have run; nullify to prevent leakage
|
|
599
|
+
pruned_action.nullify_assignments(symtab)
|
|
600
|
+
ConditionalStatementAst.new(input, interval, pruned_action, condition.prune(symtab))
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
class ConcatenationExpressionAst
|
|
606
|
+
def prune(symtab, forced_type: nil)
|
|
607
|
+
value_result = value_try do
|
|
608
|
+
v = value(symtab)
|
|
609
|
+
return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
|
|
610
|
+
end
|
|
611
|
+
value_else(value_result) do
|
|
612
|
+
c = ConcatenationExpressionAst.new(
|
|
613
|
+
input, interval, @children.map { |c| c.prune(symtab) }
|
|
614
|
+
)
|
|
615
|
+
if forced_type
|
|
616
|
+
if forced_type.width < type(symtab).width
|
|
617
|
+
c = AryRangeAccessAst.new(
|
|
618
|
+
input, interval, c, PruneHelpers.create_int_literal(forced_type.width - 1), create_int_literal(0)
|
|
619
|
+
)
|
|
620
|
+
elsif forced_type.width > type(symtab).width
|
|
621
|
+
extra = forced_type.width - type(symtab).width
|
|
622
|
+
mock_type = Struct.new(:width)
|
|
623
|
+
c = ConcatenationExpressionAst.new(
|
|
624
|
+
input, interval, [PruneHelpers.create_int_literal(0, forced_type: mock_type.new(extra))] + @children.map { |c| c.prune(symtab) }
|
|
625
|
+
)
|
|
626
|
+
end
|
|
627
|
+
end
|
|
628
|
+
c
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
class ReplicationExpressionAst
|
|
634
|
+
def prune(symtab, forced_type: nil)
|
|
635
|
+
value_result = value_try do
|
|
636
|
+
v = value(symtab)
|
|
637
|
+
return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
|
|
638
|
+
end
|
|
639
|
+
value_else(value_result) do
|
|
640
|
+
c = ReplicationExpressionAst.new(input, interval, n.prune(symtab), v.prune(symtab))
|
|
641
|
+
if forced_type
|
|
642
|
+
if forced_type.width < type(symtab).width
|
|
643
|
+
c = AryRangeAccessAst.new(
|
|
644
|
+
input, interval, c, PruneHelpers.create_int_literal(forced_type.width - 1), create_int_literal(0)
|
|
645
|
+
)
|
|
646
|
+
elsif forced_type.width > type(symtab).width
|
|
647
|
+
extra = forced_type.width - type(symtab).width
|
|
648
|
+
mock_type = Struct.new(:width)
|
|
649
|
+
c = ConcatenationExpressionAst.new(
|
|
650
|
+
input, interval, [PruneHelpers.create_int_literal(0, forced_type: mock_type.new(extra))] + @children.map { |c| c.prune(symtab) }
|
|
651
|
+
)
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
c
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
class IntLiteralAst
|
|
660
|
+
def prune(symtab, forced_type: nil)
|
|
661
|
+
if forced_type
|
|
662
|
+
raise "pruning error: attempt to force bitwidth when width is unknown" if forced_type.width.nil? || forced_type.width == :unknown
|
|
663
|
+
s = "#{forced_type.width}'d#{value(symtab)}"
|
|
664
|
+
IntLiteralAst.new(s, 0...s.size, s)
|
|
665
|
+
else
|
|
666
|
+
dup
|
|
667
|
+
end
|
|
668
|
+
end
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
class TernaryOperatorExpressionAst < AstNode
|
|
672
|
+
def prune(symtab, forced_type: nil)
|
|
673
|
+
value_result = value_try do
|
|
674
|
+
if condition.value(symtab)
|
|
675
|
+
return true_expression.prune(symtab, forced_type: forced_type || type(symtab))
|
|
676
|
+
else
|
|
677
|
+
return false_expression.prune(symtab, forced_type: forced_type || type(symtab))
|
|
678
|
+
end
|
|
679
|
+
end
|
|
680
|
+
value_else(value_result) do
|
|
681
|
+
TernaryOperatorExpressionAst.new(
|
|
682
|
+
input, interval,
|
|
683
|
+
condition.prune(symtab),
|
|
684
|
+
true_expression.prune(symtab),
|
|
685
|
+
false_expression.prune(symtab)
|
|
686
|
+
)
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
class CsrFieldAssignmentAst < AstNode
|
|
692
|
+
def prune(symtab, forced_type: nil)
|
|
693
|
+
CsrFieldAssignmentAst.new(input, interval, csr_field.dup, write_value.prune(symtab))
|
|
694
|
+
end
|
|
695
|
+
end
|
|
696
|
+
|
|
697
|
+
class CsrFieldReadExpressionAst < AstNode
|
|
698
|
+
def prune(symtab, forced_type: nil)
|
|
699
|
+
value_result = value_try do
|
|
700
|
+
v = value(symtab)
|
|
701
|
+
if type(symtab).width == :unknown
|
|
702
|
+
value_error "unknown width"
|
|
703
|
+
end
|
|
704
|
+
return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
|
|
705
|
+
end
|
|
706
|
+
value_else(value_result) do
|
|
707
|
+
CsrFieldReadExpressionAst.new(input, interval, @csr.dup, @field_name)
|
|
708
|
+
end
|
|
709
|
+
end
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
class CsrReadExpressionAst < AstNode
|
|
713
|
+
def prune(symtab, forced_type: nil)
|
|
714
|
+
value_result = value_try do
|
|
715
|
+
v = value(symtab)
|
|
716
|
+
if type(symtab).width == :unknown
|
|
717
|
+
value_error "unknown width"
|
|
718
|
+
end
|
|
719
|
+
return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
|
|
720
|
+
end
|
|
721
|
+
value_else(value_result) do
|
|
722
|
+
CsrReadExpressionAst.new(input, interval, @csr_name)
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
end
|
|
726
|
+
|
|
727
|
+
class BitsCastAst < AstNode
|
|
728
|
+
def prune(symtab, forced_type: nil)
|
|
729
|
+
p = expr.prune(symtab, forced_type:)
|
|
730
|
+
if p.type(symtab).kind == :bits
|
|
731
|
+
return p
|
|
732
|
+
else
|
|
733
|
+
return BitsCastAst.new(input, interval, p)
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
|
|
738
|
+
class IdAst < AstNode
|
|
739
|
+
def prune(symtab, forced_type: nil)
|
|
740
|
+
value_result = value_try do
|
|
741
|
+
value_error "Not pruning struct types" if type(symtab).kind == :struct
|
|
742
|
+
v = value(symtab)
|
|
743
|
+
if type(symtab).kind == :bits
|
|
744
|
+
if type(symtab).width == :unknown
|
|
745
|
+
value_error "Unknown width"
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
749
|
+
end
|
|
750
|
+
value_else(value_result) do
|
|
751
|
+
dup
|
|
752
|
+
end
|
|
753
|
+
end
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
class UnaryOperatorExpressionAst < AstNode
|
|
757
|
+
def prune(symtab, forced_type: nil)
|
|
758
|
+
value_result = value_try do
|
|
759
|
+
v = value(symtab)
|
|
760
|
+
if type(symtab).kind == :bits
|
|
761
|
+
if type(symtab).width == :unknown
|
|
762
|
+
value_error "Unknown width"
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
766
|
+
end
|
|
767
|
+
value_else(value_result) do
|
|
768
|
+
UnaryOperatorExpressionAst.new(input, interval, @op, exp.prune(symtab, forced_type:))
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
|
|
773
|
+
class AryElementAccessAst < AstNode
|
|
774
|
+
def prune(symtab, forced_type: nil)
|
|
775
|
+
value_result = value_try do
|
|
776
|
+
v = value(symtab)
|
|
777
|
+
if type(symtab).kind == :bits
|
|
778
|
+
if type(symtab).width == :unknown
|
|
779
|
+
value_error "Unknown width"
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
783
|
+
end
|
|
784
|
+
value_else(value_result) do
|
|
785
|
+
AryElementAccessAst.new(input, interval, var.prune(symtab), index.prune(symtab))
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
class AryRangeAccessAst < AstNode
|
|
791
|
+
def prune(symtab, forced_type: nil)
|
|
792
|
+
value_result = value_try do
|
|
793
|
+
v = value(symtab)
|
|
794
|
+
if type(symtab).width == :unknown
|
|
795
|
+
value_error "Unknown width"
|
|
796
|
+
end
|
|
797
|
+
return PruneHelpers.create_int_literal(v, forced_type: forced_type || type(symtab))
|
|
798
|
+
end
|
|
799
|
+
value_else(value_result) do
|
|
800
|
+
AryRangeAccessAst.new(input, interval, var.prune(symtab), msb.prune(symtab), lsb.prune(symtab))
|
|
801
|
+
end
|
|
802
|
+
end
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
class FieldAccessExpressionAst < AstNode
|
|
806
|
+
def prune(symtab, forced_type: nil)
|
|
807
|
+
value_result = value_try do
|
|
808
|
+
v = value(symtab)
|
|
809
|
+
if type(symtab).kind == :bits
|
|
810
|
+
if type(symtab).width == :unknown
|
|
811
|
+
value_error "Unknown width"
|
|
812
|
+
end
|
|
813
|
+
end
|
|
814
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
815
|
+
end
|
|
816
|
+
value_else(value_result) do
|
|
817
|
+
FieldAccessExpressionAst.new(input, interval, obj.prune(symtab), @field_name)
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
class EnumRefAst < AstNode
|
|
823
|
+
def prune(symtab, forced_type: nil)
|
|
824
|
+
value_result = value_try do
|
|
825
|
+
v = value(symtab)
|
|
826
|
+
return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
|
|
827
|
+
end
|
|
828
|
+
value_else(value_result) do
|
|
829
|
+
dup
|
|
830
|
+
end
|
|
831
|
+
end
|
|
832
|
+
end
|
|
833
|
+
|
|
834
|
+
class ReturnStatementAst < AstNode
|
|
835
|
+
def prune(symtab, forced_type: nil)
|
|
836
|
+
ReturnStatementAst.new(input, interval, return_expression.prune(symtab))
|
|
837
|
+
end
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
class ReturnExpressionAst < AstNode
|
|
841
|
+
def prune(symtab, forced_type: nil)
|
|
842
|
+
ReturnExpressionAst.new(input, interval, return_value_nodes.map { |n| n.prune(symtab) })
|
|
843
|
+
end
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
class MultiVariableAssignmentAst < AstNode
|
|
847
|
+
def prune(symtab, forced_type: nil)
|
|
848
|
+
new_ast = MultiVariableAssignmentAst.new(
|
|
849
|
+
input, interval,
|
|
850
|
+
variables.map(&:dup),
|
|
851
|
+
function_call.prune(symtab)
|
|
852
|
+
)
|
|
853
|
+
value_try do
|
|
854
|
+
new_ast.execute(symtab)
|
|
855
|
+
end
|
|
856
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
857
|
+
new_ast
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
class AryElementAssignmentAst < AstNode
|
|
862
|
+
def prune(symtab, forced_type: nil)
|
|
863
|
+
new_ast = AryElementAssignmentAst.new(
|
|
864
|
+
input, interval,
|
|
865
|
+
lhs.dup,
|
|
866
|
+
idx.prune(symtab),
|
|
867
|
+
rhs.prune(symtab)
|
|
868
|
+
)
|
|
869
|
+
value_try do
|
|
870
|
+
new_ast.execute(symtab)
|
|
871
|
+
end
|
|
872
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
873
|
+
new_ast
|
|
874
|
+
end
|
|
875
|
+
end
|
|
876
|
+
|
|
877
|
+
class AryRangeAssignmentAst < AstNode
|
|
878
|
+
def prune(symtab, forced_type: nil)
|
|
879
|
+
new_ast = AryRangeAssignmentAst.new(
|
|
880
|
+
input, interval,
|
|
881
|
+
variable.dup,
|
|
882
|
+
msb.prune(symtab),
|
|
883
|
+
lsb.prune(symtab),
|
|
884
|
+
write_value.prune(symtab)
|
|
885
|
+
)
|
|
886
|
+
value_try do
|
|
887
|
+
new_ast.execute(symtab)
|
|
888
|
+
end
|
|
889
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
890
|
+
new_ast
|
|
891
|
+
end
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
class FieldAssignmentAst < AstNode
|
|
895
|
+
def prune(symtab, forced_type: nil)
|
|
896
|
+
new_ast = FieldAssignmentAst.new(
|
|
897
|
+
input, interval,
|
|
898
|
+
id.dup,
|
|
899
|
+
@field_name,
|
|
900
|
+
rhs.prune(symtab)
|
|
901
|
+
)
|
|
902
|
+
value_try do
|
|
903
|
+
new_ast.execute(symtab)
|
|
904
|
+
end
|
|
905
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
906
|
+
new_ast
|
|
907
|
+
end
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
class VariableDeclarationAst < AstNode
|
|
911
|
+
def prune(symtab, forced_type: nil)
|
|
912
|
+
add_symbol(symtab)
|
|
913
|
+
dup
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
class MultiVariableDeclarationAst < AstNode
|
|
918
|
+
def prune(symtab, forced_type: nil)
|
|
919
|
+
add_symbol(symtab)
|
|
920
|
+
dup
|
|
921
|
+
end
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
class PostIncrementExpressionAst < AstNode
|
|
925
|
+
def prune(symtab, forced_type: nil)
|
|
926
|
+
new_ast = PostIncrementExpressionAst.new(input, interval, rval.dup)
|
|
927
|
+
value_try do
|
|
928
|
+
new_ast.execute(symtab)
|
|
929
|
+
end
|
|
930
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
931
|
+
new_ast
|
|
932
|
+
end
|
|
933
|
+
end
|
|
934
|
+
|
|
935
|
+
class PostDecrementExpressionAst < AstNode
|
|
936
|
+
def prune(symtab, forced_type: nil)
|
|
937
|
+
new_ast = PostDecrementExpressionAst.new(input, interval, rval.dup)
|
|
938
|
+
value_try do
|
|
939
|
+
new_ast.execute(symtab)
|
|
940
|
+
end
|
|
941
|
+
# value_else: execute already sets nil on failure, nothing more to do
|
|
942
|
+
new_ast
|
|
943
|
+
end
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
class PcAssignmentAst < AstNode
|
|
947
|
+
def prune(symtab, forced_type: nil)
|
|
948
|
+
PcAssignmentAst.new(input, interval, rhs.prune(symtab))
|
|
949
|
+
end
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
class CsrSoftwareWriteAst < AstNode
|
|
953
|
+
def prune(symtab, forced_type: nil)
|
|
954
|
+
CsrSoftwareWriteAst.new(input, interval, csr.dup, expression.prune(symtab))
|
|
955
|
+
end
|
|
956
|
+
end
|
|
957
|
+
end
|