Warning: session_start(): Session cannot be started after headers have already been sent in /home/tvrreohg/public_html/manga.php on line 13
# frozen_string_literal: true
module Puppet::Pops
module Evaluator
# AccessOperator handles operator []
# This operator is part of evaluation.
#
class AccessOperator
# Provides access to the Puppet 3.x runtime (scope, etc.)
# This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
#
include Runtime3Support
attr_reader :semantic
# Initialize with AccessExpression to enable reporting issues
# @param access_expression [Model::AccessExpression] the semantic object being evaluated
# @return [void]
#
def initialize(access_expression)
@@access_visitor ||= Visitor.new(self, "access", 2, nil)
@semantic = access_expression
end
def access(o, scope, *keys)
@@access_visitor.visit_this_2(self, o, scope, keys)
end
protected
def access_Object(o, scope, keys)
type = Puppet::Pops::Types::TypeCalculator.infer_callable_methods_t(o)
if type.is_a?(Puppet::Pops::Types::TypeWithMembers)
access_func = type['[]']
return access_func.invoke(o, scope, keys) unless access_func.nil?
end
fail(Issues::OPERATOR_NOT_APPLICABLE, @semantic.left_expr, :operator => '[]', :left_value => o)
end
def access_Binary(o, scope, keys)
Puppet::Pops::Types::PBinaryType::Binary.from_binary_string(access_String(o.binary_buffer, scope, keys))
end
def access_String(o, scope, keys)
keys.flatten!
result = case keys.size
when 0
fail(Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, { :actual => keys.size })
when 1
# Note that Ruby 1.8.7 requires a length of 1 to produce a String
k1 = Utils.to_n(keys[0])
bad_string_access_key_type(o, 0, k1.nil? ? keys[0] : k1) unless k1.is_a?(Integer)
k2 = 1
k1 = k1 < 0 ? o.length + k1 : k1 # abs pos
# if k1 is outside, a length of 1 always produces an empty string
if k1 < 0
EMPTY_STRING
else
o[k1, k2]
end
when 2
k1 = Utils.to_n(keys[0])
k2 = Utils.to_n(keys[1])
[k1, k2].each_with_index { |k, i| bad_string_access_key_type(o, i, k.nil? ? keys[i] : k) unless k.is_a?(Integer) }
k1 = k1 < 0 ? o.length + k1 : k1 # abs pos (negative is count from end)
k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2 # abs length (negative k2 is length from pos to end count)
# if k1 is outside, adjust to first position, and adjust length
if k1 < 0
k2 += k1
k1 = 0
end
o[k1, k2]
else
fail(Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, { :actual => keys.size })
end
# Specified as: an index outside of range, or empty result == empty string
(result.nil? || result.empty?) ? EMPTY_STRING : result
end
# Parameterizes a PRegexp Type with a pattern string or r ruby egexp
#
def access_PRegexpType(o, scope, keys)
keys.flatten!
unless keys.size == 1
blamed = keys.size == 0 ? @semantic : @semantic.keys[1]
fail(Issues::BAD_TYPE_SLICE_ARITY, blamed, :base_type => o, :min => 1, :actual => keys.size)
end
assert_keys(keys, o, 1, 1, String, Regexp)
Types::TypeFactory.regexp(*keys)
end
# Evaluates [] with 1 or 2 arguments. One argument is an index lookup, two arguments is a slice from/to.
#
def access_Array(o, scope, keys)
keys.flatten!
case keys.size
when 0
fail(Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, { :actual => keys.size })
when 1
key = coerce_numeric(keys[0], @semantic.keys[0], scope)
unless key.is_a?(Integer)
bad_access_key_type(o, 0, key, Integer)
end
o[key]
when 2
# A slice [from, to] with support for -1 to mean start, or end respectively.
k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
k2 = coerce_numeric(keys[1], @semantic.keys[1], scope)
[k1, k2].each_with_index { |k, i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
# Help confused Ruby do the right thing (it truncates to the right, but negative index + length can never overlap
# the available range.
k1 = k1 < 0 ? o.length + k1 : k1 # abs pos (negative is count from end)
k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2 # abs length (negative k2 is length from pos to end count)
# if k1 is outside, adjust to first position, and adjust length
if k1 < 0
k2 += k1
k1 = 0
end
# Help ruby always return empty array when asking for a sub array
result = o[k1, k2]
result.nil? ? [] : result
else
fail(Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, { :actual => keys.size })
end
end
# Evaluates [] with support for one or more arguments. If more than one argument is used, the result
# is an array with each lookup.
# @note
# Does not flatten its keys to enable looking up with a structure
#
def access_Hash(o, scope, keys)
# Look up key in hash, if key is nil, try alternate form (:undef) before giving up.
# This is done because the hash may have been produced by 3x logic and may thus contain :undef.
result = keys.collect do |k|
o.fetch(k) { |key| key.nil? ? o[:undef] : nil }
end
case result.size
when 0
fail(Issues::BAD_HASH_SLICE_ARITY, @semantic.left_expr, { :actual => keys.size })
when 1
result.pop
else
# remove nil elements and return
result.compact!
result
end
end
def access_PBooleanType(o, scope, keys)
keys.flatten!
assert_keys(keys, o, 1, 1, TrueClass, FalseClass)
Types::TypeFactory.boolean(keys[0])
end
def access_PEnumType(o, scope, keys)
keys.flatten!
last = keys.last
case_insensitive = false
if last == true || last == false
keys = keys[0...-1]
case_insensitive = last
end
assert_keys(keys, o, 1, Float::INFINITY, String)
Types::PEnumType.new(keys, case_insensitive)
end
def access_PVariantType(o, scope, keys)
keys.flatten!
assert_keys(keys, o, 1, Float::INFINITY, Types::PAnyType)
Types::TypeFactory.variant(*keys)
end
def access_PSemVerType(o, scope, keys)
keys.flatten!
assert_keys(keys, o, 1, Float::INFINITY, String, SemanticPuppet::VersionRange)
Types::TypeFactory.sem_ver(*keys)
end
def access_PTimestampType(o, scope, keys)
keys.flatten!
fail(Issues::BAD_TYPE_SLICE_ARITY, @semantic, :base_type => o, :min => 0, :max => 2, :actual => keys.size) if keys.size > 2
Types::TypeFactory.timestamp(*keys)
end
def access_PTimespanType(o, scope, keys)
keys.flatten!
fail(Issues::BAD_TYPE_SLICE_ARITY, @semantic, :base_type => o, :min => 0, :max => 2, :actual => keys.size) if keys.size > 2
Types::TypeFactory.timespan(*keys)
end
def access_PTupleType(o, scope, keys)
keys.flatten!
if Types::TypeFactory.is_range_parameter?(keys[-2]) && Types::TypeFactory.is_range_parameter?(keys[-1])
size_type = Types::TypeFactory.range(keys[-2], keys[-1])
keys = keys[0, keys.size - 2]
elsif Types::TypeFactory.is_range_parameter?(keys[-1])
size_type = Types::TypeFactory.range(keys[-1], :default)
keys = keys[0, keys.size - 1]
end
assert_keys(keys, o, 1, Float::INFINITY, Types::PAnyType)
Types::TypeFactory.tuple(keys, size_type)
end
def access_PCallableType(o, scope, keys)
if keys.size > 0 && keys[0].is_a?(Array)
unless keys.size == 2
fail(Issues::BAD_TYPE_SLICE_ARITY, @semantic, :base_type => o, :min => 2, :max => 2, :actual => keys.size)
end
unless keys[1].is_a?(Types::PAnyType)
bad_type_specialization_key_type(o, 1, k, Types::PAnyType)
end
end
Types::TypeFactory.callable(*keys)
end
def access_PStructType(o, scope, keys)
assert_keys(keys, o, 1, 1, Hash)
Types::TypeFactory.struct(keys[0])
end
def access_PStringType(o, scope, keys)
keys.flatten!
case keys.size
when 1
size_t = collection_size_t(0, keys[0])
when 2
size_t = collection_size_t(0, keys[0], keys[1])
else
fail(Issues::BAD_STRING_SLICE_ARITY, @semantic, { :actual => keys.size })
end
Types::TypeFactory.string(size_t)
end
# Asserts type of each key and calls fail with BAD_TYPE_SPECIFICATION
# @param keys [Array