Class: Idl::UnaryOperatorExpressionAst

Inherits:
AstNode
  • Object
show all
Includes:
Rvalue
Defined in:
lib/idlc/ast.rb,
lib/idlc/passes/prune.rb,
lib/idlc/passes/gen_adoc.rb

Overview

represents a unary operator

for example:

-value
~value
!bool_variable

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

Methods included from Rvalue

#max_value, #min_value, #truncate, #values

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, #gen_option_adoc, #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, op, expression) ⇒ UnaryOperatorExpressionAst

Returns a new instance of UnaryOperatorExpressionAst.



6192
6193
6194
6195
6196
6197
# File 'lib/idlc/ast.rb', line 6192

def initialize(input, interval, op, expression)
  super(input, interval, [expression])

  raise "Bad op #{op.inspect}" unless ["~", "!", "-"].include?(op)
  @op = op
end

Class Method Details

.from_h(yaml, source_mapper) ⇒ Object



6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
# File 'lib/idlc/ast.rb', line 6304

def self.from_h(yaml, source_mapper)
  raise "Bad YAML" unless yaml.key?("kind") && yaml.fetch("kind") == "unary_operator_expr"

  input = input_from_source_yaml(yaml.fetch("source"), source_mapper)
  interval = interval_from_source_yaml(yaml.fetch("source"))
  UnaryOperatorExpressionAst.new(
    input, interval,
    yaml.fetch("op"),
    AstNode.from_h(yaml.fetch("expr"), source_mapper)
  )
end

Instance Method Details

#const_eval?(symtab) ⇒ Boolean

Returns:

  • (Boolean)


6188
# File 'lib/idlc/ast.rb', line 6188

def const_eval?(symtab) = expression.const_eval?(symtab)

#expAstNode

Returns the operated-on expression.

Returns:

  • (AstNode)

    the operated-on expression



6282
6283
6284
# File 'lib/idlc/ast.rb', line 6282

def exp
  expression
end

#expressionObject



6190
# File 'lib/idlc/ast.rb', line 6190

def expression = @children[0]

#gen_adoc(indent = 0, indent_spaces: 2) ⇒ Object



270
271
272
# File 'lib/idlc/passes/gen_adoc.rb', line 270

def gen_adoc(indent = 0, indent_spaces: 2)
  "#{' ' * indent}#{op}#{exp.gen_adoc(0, indent_spaces:)}"
end

#invert(symtab) ⇒ Object



6199
6200
6201
6202
6203
6204
6205
6206
6207
# File 'lib/idlc/ast.rb', line 6199

def invert(symtab)
  unless symtab.nil?
    type_error "Not a boolean operator" unless type(symtab).kind == :boolean
  end

  type_error "Invert only works with !" unless op == "!"

  expression
end

#opString

Returns The operator.

Returns:

  • (String)

    The operator



6287
6288
6289
# File 'lib/idlc/ast.rb', line 6287

def op
  @op
end

#prune(symtab, forced_type: nil) ⇒ Object



791
792
793
794
795
796
797
798
799
800
801
802
803
804
# File 'lib/idlc/passes/prune.rb', line 791

def prune(symtab, forced_type: nil)
  value_result = value_try do
    v = value(symtab)
    if type(symtab).kind == :bits
      if type(symtab).width == :unknown
        value_error "Unknown width"
      end
    end
    return PruneHelpers.create_literal(symtab, v, type(symtab), forced_type: forced_type || type(symtab))
  end
  value_else(value_result) do
    UnaryOperatorExpressionAst.new(input, interval, @op, exp.prune(symtab, forced_type:))
  end
end

#to_hObject



6296
6297
6298
6299
6300
6301
# File 'lib/idlc/ast.rb', line 6296

def to_h = {
  "kind" => "unary_operator_expr",
  "op" => op,
  "expr" => expression.to_h,
  "source" => source_yaml
}

#to_idlObject



6293
# File 'lib/idlc/ast.rb', line 6293

def to_idl = "#{op}#{expression.to_idl}"

#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

Parameters:

Returns:

  • (Type)

    The type of the node

Raises:



6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
# File 'lib/idlc/ast.rb', line 6210

def type(symtab)
  case op
  when "-", "~"
    exp.type(symtab).clone
  when "!"
    if exp.type(symtab).const?
      ConstBoolType
    else
      BoolType
    end
  else
    internal_error "unhandled op #{op}"
  end
end

#type_check(symtab, strict:) ⇒ void

This method returns an undefined value.

type check this node and all children

Calls to #type and/or #value may depend on type_check being called first with the same symtab. If not, those functions may raise an AstNode::InternalError

Parameters:

Raises:



6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
# File 'lib/idlc/ast.rb', line 6226

def type_check(symtab, strict:)
  exp.type_check(symtab, strict:)

  case op
  when "-"
    unless [:bits, :bitfield].include?(exp.type(symtab).kind)
      type_error "#{exp.type(symtab)} does not support unary #{op} operator"
    end

    # type_error "Unary minus only works on signed values" unless exp.type(symtab).signed?
  when "~"
    unless [:bits, :bitfield].include?(exp.type(symtab).kind)
      type_error "#{exp.type(symtab)} does not support unary #{op} operator"
    end
  when "!"
    unless exp.type(symtab).convertable_to?(:boolean)
      if exp.type(symtab).kind == :bits
        type_error "#{exp.type(symtab)} does not support unary #{op} operator. Perhaps you want '#{exp.text_value} != 0'?"
      else
        type_error "#{exp.type(symtab)} does not support unary #{op} operator"
      end
    end
  else
    internal_error "Unhandled op #{op}"
  end
end

#value(symtab) ⇒ Object

Return the compile-time-known value of the node



6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
# File 'lib/idlc/ast.rb', line 6254

def value(symtab)
  val = val_trunc =
    case op
    when "-"
      -exp.value(symtab)
    when "~"
      ~exp.value(symtab)
    when "!"
      !exp.value(symtab)
    else
      internal_error "Unhandled unary op #{op}"
    end
  t = type(symtab)
  if t.integral?
    if t.width == :unknown
      value_error("Unknown width for truncation")
    end
    val_trunc = truncate(val, t.width, t.signed?)
  end

  if op != "~"
    truncation_warn "#{text_value} is truncated due to insufficient bit width (from #{val} to #{val_trunc})" if val_trunc != val
  end

  val_trunc
end