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.



6207
6208
6209
6210
6211
6212
# File 'lib/idlc/ast.rb', line 6207

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



6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329
# File 'lib/idlc/ast.rb', line 6319

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)


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

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

#expAstNode

Returns the operated-on expression.

Returns:

  • (AstNode)

    the operated-on expression



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

def exp
  expression
end

#expressionObject



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

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



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

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



6302
6303
6304
# File 'lib/idlc/ast.rb', line 6302

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



6311
6312
6313
6314
6315
6316
# File 'lib/idlc/ast.rb', line 6311

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

#to_idlObject



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

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:



6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
# File 'lib/idlc/ast.rb', line 6225

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:



6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
# File 'lib/idlc/ast.rb', line 6241

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



6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
# File 'lib/idlc/ast.rb', line 6269

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