Class: Idl::TernaryOperatorExpressionAst
- Includes:
- Rvalue
- Defined in:
- lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb,
lib/idlc/passes/gen_option_adoc.rb
Overview
Represents a ternary operator
for example:
condition ? a : b
(a < b) ? c : d
Defined Under Namespace
Classes: Memo
Constant Summary
Constants inherited from AstNode
AstNode::Bits1Type, AstNode::Bits32Type, AstNode::Bits64Type, AstNode::BoolType, AstNode::ConstBoolType, AstNode::PossiblyUnknownBits1Type, AstNode::PossiblyUnknownBits32Type, AstNode::PossiblyUnknownBits64Type, AstNode::ReachableFunctionCacheType, AstNode::StringType, AstNode::VoidType
Instance Attribute Summary
Attributes inherited from AstNode
#children, #input, #interval, #parent
Class Method Summary collapse
Instance Method Summary collapse
- #condition ⇒ Object
- #const_eval?(symtab) ⇒ Boolean
- #false_expression ⇒ Object
- #gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
- #gen_option_adoc ⇒ Object
-
#initialize(input, interval, condition, true_expression, false_expression) ⇒ TernaryOperatorExpressionAst
constructor
A new instance of TernaryOperatorExpressionAst.
- #max_value(symtab) ⇒ Object
- #min_value(symtab) ⇒ Object
- #prune(symtab, forced_type: nil) ⇒ Object
- #to_h ⇒ Object
- #to_idl ⇒ Object
- #true_expression ⇒ Object
-
#type(symtab) ⇒ Type
Given a specific symbol table, return the type of this node.
-
#type_check(symtab, strict:) ⇒ void
type check this node and all children.
-
#value(symtab) ⇒ Object
Return the compile-time-known value of the node.
-
#values(symtab) ⇒ Array<Integer>, ...
Return a complete list of possible compile-time-known values of the node, or raise a ValueError if the full list cannot be determined.
Methods included from Rvalue
Methods inherited from AstNode
#always_terminates?, #declaration?, #executable?, extract_base_var_name, #find_ancestor, #find_dst_registers, #find_referenced_csrs, #find_src_registers, #freeze_tree, #input_file, input_from_source_yaml, #inspect, #internal_error, interval_from_source_yaml, #lineno, #lines_around, #nullify_assignments, #pass_find_return_values, #path, #print_ast, #reachable_exceptions, #reachable_functions, #set_input_file, #set_input_file_unless_already_set, #source_line_file_offsets, #source_starting_offset, #source_yaml, #starting_line, #text_value, #truncation_warn, #type_error, #unindent, value_else, #value_else, value_error, #value_error, value_try, #value_try, write_back_nested
Constructor Details
#initialize(input, interval, condition, true_expression, false_expression) ⇒ TernaryOperatorExpressionAst
Returns a new instance of TernaryOperatorExpressionAst.
6367 6368 6369 6370 |
# File 'lib/idlc/ast.rb', line 6367 def initialize(input, interval, condition, true_expression, false_expression) super(input, interval, [condition, true_expression, false_expression]) @memo = Memo.new end |
Class Method Details
.from_h(yaml, source_mapper) ⇒ Object
6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 |
# File 'lib/idlc/ast.rb', line 6523 def self.from_h(yaml, source_mapper) raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "ternary_operator_expr" input = input_from_source_yaml(yaml.fetch("source"), source_mapper) interval = interval_from_source_yaml(yaml.fetch("source")) TernaryOperatorExpressionAst.new( input, interval, T.cast(AstNode.from_h(yaml.fetch("condition"), source_mapper), RvalueAst), T.cast(AstNode.from_h(yaml.fetch("true_expression"), source_mapper), RvalueAst), T.cast(AstNode.from_h(yaml.fetch("false_expression"), source_mapper), RvalueAst) ) end |
Instance Method Details
#condition ⇒ Object
6353 |
# File 'lib/idlc/ast.rb', line 6353 def condition = @children[0] |
#const_eval?(symtab) ⇒ Boolean
6351 |
# File 'lib/idlc/ast.rb', line 6351 def const_eval?(symtab) = condition.const_eval?(symtab) && true_expression.const_eval?(symtab) && false_expression.const_eval?(symtab) |
#false_expression ⇒ Object
6355 |
# File 'lib/idlc/ast.rb', line 6355 def false_expression = @children[2] |
#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object
191 192 193 |
# File 'lib/idlc/passes/gen_adoc.rb', line 191 def gen_adoc(indent = 0, indent_spaces: 2) "#{' ' * indent}#{condition.gen_adoc(0, indent_spaces:)} ? #{true_expression.gen_adoc(0, indent_spaces:)} : #{false_expression.gen_adoc(0, indent_spaces:)}" end |
#gen_option_adoc ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/idlc/passes/gen_option_adoc.rb', line 123 def gen_option_adoc cond = condition.is_a?(ParenExpressionAst) ? condition.expression : condition if cond.is_a?(BinaryExpressionAst) || cond.is_a?(UnaryOperatorExpressionAst) <<~ADOC [when,"#{cond.gen_adoc.gsub('"', """)}"] #{true_expression.gen_option_adoc} [when,"#{cond.invert(nil).gen_adoc.gsub('"', """)}"] #{false_expression.gen_option_adoc} ADOC else <<~ADOC [when,"#{cond.gen_adoc.gsub('"', """)}"] #{true_expression.gen_option_adoc} [when,"!(#{cond.gen_adoc.gsub('"', """)})"] #{false_expression.gen_option_adoc} ADOC end end |
#max_value(symtab) ⇒ Object
6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 |
# File 'lib/idlc/ast.rb', line 6482 def max_value(symtab) value_result = value_try do cond = condition.value(symtab) return cond ? true_expression.max_value(symtab) : false_expression.max_value(symtab) end value_else(value_result) do t = true_expression.max_value(symtab) f = false_expression.max_value(symtab) return :unknown if t == :unknown || f == :unknown [t, f].max end end |
#min_value(symtab) ⇒ Object
6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 |
# File 'lib/idlc/ast.rb', line 6496 def min_value(symtab) value_result = value_try do cond = condition.value(symtab) return cond ? true_expression.min_value(symtab) : false_expression.min_value(symtab) end value_else(value_result) do t = true_expression.min_value(symtab) f = false_expression.min_value(symtab) return :unknown if t == :unknown || f == :unknown [t, f].min end end |
#prune(symtab, forced_type: nil) ⇒ Object
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 |
# File 'lib/idlc/passes/prune.rb', line 706 def prune(symtab, forced_type: nil) value_result = value_try do if condition.value(symtab) return true_expression.prune(symtab, forced_type: forced_type || type(symtab)) else return false_expression.prune(symtab, forced_type: forced_type || type(symtab)) end end value_else(value_result) do TernaryOperatorExpressionAst.new( input, interval, condition.prune(symtab), true_expression.prune(symtab), false_expression.prune(symtab) ) end end |
#to_h ⇒ Object
6514 6515 6516 6517 6518 6519 6520 |
# File 'lib/idlc/ast.rb', line 6514 def to_h = { "kind" => "ternary_operator_expr", "condition" => condition.to_h, "true_expression" => true_expression.to_h, "false_expression" => false_expression.to_h, "source" => source_yaml } |
#to_idl ⇒ Object
6511 |
# File 'lib/idlc/ast.rb', line 6511 def to_idl = "#{condition.to_idl} ? #{true_expression.to_idl} : #{false_expression.to_idl}" |
#true_expression ⇒ Object
6354 |
# File 'lib/idlc/ast.rb', line 6354 def true_expression = @children[1] |
#type(symtab) ⇒ Type
Given a specific symbol table, return the type of this node.
Should not be called until #type_check is called with the same arguments
6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 |
# File 'lib/idlc/ast.rb', line 6412 def type(symtab) key = "#{symtab.name}/#{symtab.mxlen}" return @memo.type.fetch(key) if @memo.type.key?(key) t = if true_expression.type(symtab).kind == :bits && false_expression.type(symtab).kind == :bits true_type = true_expression.type(symtab) false_type = false_expression.type(symtab) true_width = true_type.width false_width = false_type.width known = true_expression.type(symtab).known? && false_expression.type(symtab).known? if true_width == :unknown || false_width == :unknown max_width = if true_width == :unknown && false_width == :unknown if true_type.max_width.nil? || false_type.max_width.nil? nil else [true_type.max_width, false_type.max_width].max end elsif true_width == :unknown if true_type.max_width.nil? nil else [true_type.max_width, false_width].max end elsif false_width == :unknown if false_type.max_width.nil? nil else [false_type.max_width, true_width].max end else raise "unreachable" end if known Type.new(:bits, width: :unknown, max_width:, qualifiers: [:known]) else Type.new(:bits, width: :unknown, max_width:) end else if known Type.new(:bits, width: [true_width, false_width].max, qualifiers: [:known]) else Type.new(:bits, width: [true_width, false_width].max) end end else true_expression.type(symtab).clone end if condition.type(symtab).const? && true_expression.type(symtab).const? && false_expression.type(symtab).const? t.make_const! end @memo.type[key] = t end |
#type_check(symtab, strict:) ⇒ void
6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 |
# File 'lib/idlc/ast.rb', line 6373 def type_check(symtab, strict:) condition.type_check(symtab, strict:) if condition.type(symtab).kind == :bits type_error "ternary selector must be bool (maybe you meant '#{condition.text_value} != 0'?)" else type_error "ternary selector must be bool" unless condition.type(symtab).kind == :boolean end if strict value_result = value_try do cond = condition.value(symtab) # if the condition is compile-time-known, only check the used field cond ? true_expression.type_check(symtab, strict:) : false_expression.type_check(symtab, strict:) end value_else(value_result) do true_expression.type_check(symtab, strict:) false_expression.type_check(symtab, strict:) unless true_expression.type(symtab).equal_to?(false_expression.type(symtab)) # we'll allow dissimilar if they are both bits type unless true_expression.type(symtab).kind == :bits && false_expression.type(symtab).kind == :bits type_error "True and false options must be same type (have #{true_expression.type(symtab)} and #{false_expression.type(symtab)})" end end end else true_expression.type_check(symtab, strict:) false_expression.type_check(symtab, strict:) unless true_expression.type(symtab).equal_to?(false_expression.type(symtab)) # we'll allow dissimilar if they are both bits type unless true_expression.type(symtab).kind == :bits && false_expression.type(symtab).kind == :bits type_error "True and false options must be same type (have #{true_expression.type(symtab)} and #{false_expression.type(symtab)})" end end end end |
#value(symtab) ⇒ Object
Return the compile-time-known value of the node
6467 6468 6469 |
# File 'lib/idlc/ast.rb', line 6467 def value(symtab) condition.value(symtab) ? true_expression.value(symtab) : false_expression.value(symtab) end |
#values(symtab) ⇒ Array<Integer>, ...
Return a complete list of possible compile-time-known values of the node, or raise a ValueError if the full list cannot be determined
For most AstNodes, this will just be a single-entry array
6472 6473 6474 6475 6476 6477 6478 6479 |
# File 'lib/idlc/ast.rb', line 6472 def values(symtab) value_result = value_try do return condition.value(symtab) ? true_expression.values(symtab) : false_expression.values(symtab) end value_else(value_result) do (true_expression.values(symtab) + false_expression.values(symtab)).uniq end end |