Class: Puppet::Functions::Function3x

Inherits:
InternalFunction show all
Defined in:
lib/puppet/functions.rb

Constant Summary collapse

PARAM_NAMES =

Table of optimized parameter names - 0 to 5 parameters

[
  [],
  ['p0'.freeze].freeze,
  ['p0'.freeze, 'p1'.freeze].freeze,
  ['p0'.freeze, 'p1'.freeze, 'p2'.freeze].freeze,
  ['p0'.freeze, 'p1'.freeze, 'p2'.freeze, 'p3'.freeze].freeze,
  ['p0'.freeze, 'p1'.freeze, 'p2'.freeze, 'p3'.freeze, 'p4'.freeze].freeze,
]

Instance Attribute Summary

Attributes inherited from Pops::Functions::Function

#closure_scope, #loader

Class Method Summary collapse

Methods inherited from InternalFunction

builder, #call_function_with_scope

Methods inherited from Function

argument_mismatch, builder, dispatch, local_types, new

Methods inherited from Pops::Functions::Function

#call, #call_function, dispatcher, #initialize, signatures

Constructor Details

This class inherits a constructor from Puppet::Pops::Functions::Function

Class Method Details

.create_function(func_name, func_info, loader) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates an anonymous Function3x class that wraps a 3x function


697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
# File 'lib/puppet/functions.rb', line 697

def self.create_function(func_name, func_info, loader)
  func_name = func_name.to_s

  # Creates an anonymous class to represent the function
  # The idea being that it is garbage collected when there are no more
  # references to it.
  #
  # (Do not give the class the block here, as instance variables should be set first)
  the_class = Class.new(Function3x)

  unless loader.nil?
    the_class.instance_variable_set(:'@loader', loader.private_loader)
  end

  the_class.instance_variable_set(:'@func_name', func_name)
  the_class.instance_variable_set(:'@method3x', :"function_#{func_name}")

  # Make the anonymous class appear to have the class-name <func_name>
  # Even if this class is not bound to such a symbol in a global ruby scope and
  # must be resolved via the loader.
  # This also overrides any attempt to define a name method in the given block
  # (Since it redefines it)
  #
  the_class.instance_eval do
    def name
      @func_name
    end

    def loader
      @loader
    end

    def method3x
      @method3x
    end
  end

  # Add the method that is called - it simply delegates to
  # the 3.x function by calling it via the calling scope using the @method3x symbol
  # :"function_#{name}".
  #
  # When function is not an rvalue function, make sure it produces nil
  #
  the_class.class_eval do

    # Bypasses making the  call via the dispatcher to make sure errors
    # are reported exactly the same way as in 3x. The dispatcher is still needed as it is
    # used to support other features than calling.
    #
    def call(scope, *args, &block)
      begin
        result = catch(:return) do
          mapped_args = Puppet::Pops::Evaluator::Runtime3FunctionArgumentConverter.map_args(args, scope, '')
          # this is the scope.function_xxx(...) call
          return scope.send(self.class.method3x, mapped_args)
        end
        return result.value
      rescue Puppet::Pops::Evaluator::Next => jumper
        begin
          throw :next, jumper.value
        rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
          raise Puppet::ParseError.new("next() from context where this is illegal", jumper.file, jumper.line)
        end
      rescue Puppet::Pops::Evaluator::Return => jumper
        begin
          throw :return, jumper
        rescue Puppet::Parser::Scope::UNCAUGHT_THROW_EXCEPTION
          raise Puppet::ParseError.new("return() from context where this is illegal", jumper.file, jumper.line)
        end
      end
    end
  end

  # Create a dispatcher based on func_info
  type, names = Puppet::Functions.any_signature(*from_to_names(func_info))
  last_captures_rest = (type.size_range[1] == Float::INFINITY)

  # The method '3x_function' here is a dummy as the dispatcher is not used for calling, only for information.
  the_class.dispatcher.add(Puppet::Pops::Functions::Dispatch.new(type, '3x_function', names, last_captures_rest))
  # The function class is returned as the result of the create function method
  the_class
end

.from_to_names(func_info) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Compute min and max number of arguments and a list of constructed parameter names p0 - pn (since there are no parameter names in 3x functions).


784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'lib/puppet/functions.rb', line 784

def self.from_to_names(func_info)
  arity = func_info[:arity]
  if arity.nil?
    arity = -1
  end
  if arity < 0
    from = -arity - 1 # arity -1 is 0 min param, -2 is min 1 param
    to = :default     # infinite range
    count = -arity    # the number of named parameters
  else
    count = from = to = arity
  end
  # Names of parameters, up to 5 are optimized and use frozen version
  # Note that (0..count-1) produces expected empty array for count == 0, 0-n for count >= 1
  names = count <= 5 ? PARAM_NAMES[count] : (0..count-1).map {|n| "p#{n}" }
  [from, to, names]
end