Class: ADSL::Parser::ASTAction

Inherits:
ASTNode show all
Defined in:
lib/adsl/parser/ast_nodes.rb

Instance Method Summary collapse

Methods inherited from ASTNode

#==, #adsl_ast, #adsl_ast_size, #block_replace, #dup, #hash, is_formula?, is_objset?, is_statement?, node_type, #objset_has_side_effects?, #preorder_traverse

Methods included from Verification::FormulaGenerators

#[], #and, #binary_op, #binary_op_with_any_number_of_params, #equiv, #exists, #false, #forall, #handle_quantifier, #implies, #in_formula_builder, #not, #or, #true

Methods included from Verification::Utils

#classname_for_classname, #infer_classname_from_varname, #t

Instance Method Details

#optimizeObject



571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
# File 'lib/adsl/parser/ast_nodes.rb', line 571

def optimize
  copy = dup
  copy.instance_variable_set :@pre_optimize_adsl_ast_size, copy.adsl_ast_size

  copy.block = until_no_change(copy.block) do |block|
    block = block.optimize(true)

    variables_read = []
    block.preorder_traverse do |node|
      next unless node.is_a? ASTVariable
      variables_read << node.var_name.text
    end
    block.block_replace do |node|
      next unless node.is_a? ASTAssignment
      next if node.var_name.nil? || variables_read.include?(node.var_name.text)
      ASTObjsetStmt.new :objset => node.objset
    end

    next block if block.statements.length != 1

    if block.statements.first.is_a? ASTEither
      either = block.statements.first
      either = ASTEither.new(:blocks => either.blocks.reject{ |subblock| subblock.statements.empty? })
      if either.blocks.length == 0
        ASTBlock.new(:statements => [])
      elsif either.blocks.length == 1
        either.blocks.first
      else
        ASTBlock.new(:statements => [either])
      end
    else
      block
    end
  end

  copy
end

#pre_optimize_adsl_ast_sizeObject



609
610
611
# File 'lib/adsl/parser/ast_nodes.rb', line 609

def pre_optimize_adsl_ast_size
  @pre_optimize_adsl_ast_size || adsl_ast_size
end

#prepend_global_variables_by_signatures(*regexes) ⇒ Object



613
614
615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/adsl/parser/ast_nodes.rb', line 613

def prepend_global_variables_by_signatures(*regexes)
  variable_names = []
  preorder_traverse do |node|
    next unless node.is_a? ASTVariable
    name = node.var_name.text
    variable_names << name if regexes.map{ |r| r =~ name ? true : false }.include? true
  end
  variable_names.each do |name|
    @block.statements.unshift ASTAssignment.new(
      :var_name => ASTIdent.new(:text => name),
      :objset => ASTEmptyObjset.new
    )
  end
end

#to_adslObject



628
629
630
631
632
633
634
635
636
637
638
639
# File 'lib/adsl/parser/ast_nodes.rb', line 628

def to_adsl
  args = []
  @arg_cardinalities.length.times do |index|
    card = @arg_cardinalities[index]
    type = @arg_types[index].text
    name = @arg_names[index].text

    card_str = card[1] == Float::INFINITY ? "#{card[0]}+" : "#{card[0]}..#{card[1]}"
    args << "#{card_str} #{type} #{name}"
  end
  "action #{@name.text}(#{ args.join ', ' }) {\n#{ @block.to_adsl.adsl_indent }}\n"
end

#typecheck_and_resolve(context) ⇒ Object



535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/adsl/parser/ast_nodes.rb', line 535

def typecheck_and_resolve(context)
  old_action_node, old_action = context.actions[@name.text]
  raise ADSLError, "Duplicate action name #{@name.text} on line #{@name.lineno}; first definition on line #{old_action_node.name.lineno}" unless old_action.nil?
  arguments = []
  cardinalities = []
  block = nil
  context.in_stack_frame do
    @arg_names.length.times do |i|
      cardinality = @arg_cardinalities[i]
      if cardinality[0] > cardinality[1]
        raise ADSLError, "Invalid cardinality of argument #{@arg_names[i].text} of action #{@name.text} on line #{cardinality[2]}: minimum cardinality #{cardinality[0]} must not be greater than the maximum cardinality #{cardinality[1]}"
      end
      if cardinality[1] == 0
        raise ADSLError, "Invalid cardinality of relation #{@arg_names[i].text} of action #{@name.text} on line #{cardinality[2]}: maximum cardinality #{cardinality[1]} must be positive"
      end
      cardinality = cardinality.first 2

      klass_node, klass = context.classes[@arg_types[i].text]
      raise ADSLError, "Unknown class #{@arg_types[i].text} on line #{@arg_types[i].lineno}" if klass.nil?
      var = ADSL::DS::DSVariable.new :name => @arg_names[i].text, :type => klass
      context.define_var var, @arg_types[i]
      arguments << var
      cardinalities << cardinality
    end
    block = @block.typecheck_and_resolve context, false
  end
  action = ADSL::DS::DSAction.new :name => @name.text, :args => arguments, :cardinalities => cardinalities, :block => block
  context.actions[action.name] = [self, action]
  return action
rescue Exception => e
  #pp @block
  new_ex = e.exception("#{e.message} in action #{@name.text}")
  new_ex.set_backtrace e.backtrace
  raise new_ex
end