PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/puppet/pops/evaluator/access_operator.rb

https://github.com/jeffb-bt/puppet
Ruby | 593 lines | 450 code | 54 blank | 89 comment | 56 complexity | 44c62031e07d2ea1a304e36460e41bbf MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-3.0
  1. # AccessOperator handles operator []
  2. # This operator is part of evaluation.
  3. #
  4. class Puppet::Pops::Evaluator::AccessOperator
  5. # Provides access to the Puppet 3.x runtime (scope, etc.)
  6. # This separation has been made to make it easier to later migrate the evaluator to an improved runtime.
  7. #
  8. include Puppet::Pops::Evaluator::Runtime3Support
  9. Issues = Puppet::Pops::Issues
  10. TYPEFACTORY = Puppet::Pops::Types::TypeFactory
  11. attr_reader :semantic
  12. # Initialize with AccessExpression to enable reporting issues
  13. # @param access_expression [Puppet::Pops::Model::AccessExpression] the semantic object being evaluated
  14. # @return [void]
  15. #
  16. def initialize(access_expression)
  17. @@access_visitor ||= Puppet::Pops::Visitor.new(self, "access", 2, nil)
  18. @semantic = access_expression
  19. end
  20. def access (o, scope, *keys)
  21. @@access_visitor.visit_this_2(self, o, scope, keys)
  22. end
  23. protected
  24. def access_Object(o, scope, keys)
  25. fail(Issues::OPERATOR_NOT_APPLICABLE, @semantic.left_expr, :operator=>'[]', :left_value => o)
  26. end
  27. def access_String(o, scope, keys)
  28. keys.flatten!
  29. result = case keys.size
  30. when 0
  31. fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
  32. when 1
  33. # Note that Ruby 1.8.7 requires a length of 1 to produce a String
  34. k1 = coerce_numeric(keys[0], @semantic.keys, scope)
  35. bad_access_key_type(o, 0, k1, Integer) unless k1.is_a?(Integer)
  36. k2 = 1
  37. k1 = k1 < 0 ? o.length + k1 : k1 # abs pos
  38. # if k1 is outside, a length of 1 always produces an empty string
  39. if k1 < 0
  40. ''
  41. else
  42. o[ k1, k2 ]
  43. end
  44. when 2
  45. k1 = coerce_numeric(keys[0], @semantic.keys, scope)
  46. k2 = coerce_numeric(keys[1], @semantic.keys, scope)
  47. [k1, k2].each_with_index { |k,i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
  48. k1 = k1 < 0 ? o.length + k1 : k1 # abs pos (negative is count from end)
  49. k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2 # abs length (negative k2 is length from pos to end count)
  50. # if k1 is outside, adjust to first position, and adjust length
  51. if k1 < 0
  52. k2 = k2 + k1
  53. k1 = 0
  54. end
  55. o[ k1, k2 ]
  56. else
  57. fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
  58. end
  59. # Specified as: an index outside of range, or empty result == empty string
  60. (result.nil? || result.empty?) ? '' : result
  61. end
  62. # Parameterizes a PRegexp Type with a pattern string or r ruby egexp
  63. #
  64. def access_PRegexpType(o, scope, keys)
  65. keys.flatten!
  66. unless keys.size == 1
  67. blamed = keys.size == 0 ? @semantic : @semantic.keys[1]
  68. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed, :base_type => o, :min=>1, :actual => keys.size)
  69. end
  70. assert_keys(keys, o, 1, 1, String, Regexp)
  71. Puppet::Pops::Types::TypeFactory.regexp(*keys)
  72. end
  73. # Evaluates <ary>[] with 1 or 2 arguments. One argument is an index lookup, two arguments is a slice from/to.
  74. #
  75. def access_Array(o, scope, keys)
  76. keys.flatten!
  77. case keys.size
  78. when 0
  79. fail(Puppet::Pops::Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
  80. when 1
  81. k = coerce_numeric(keys[0], @semantic.keys[0], scope)
  82. unless k.is_a?(Integer)
  83. bad_access_key_type(o, 0, k, Integer)
  84. end
  85. o[k]
  86. when 2
  87. # A slice [from, to] with support for -1 to mean start, or end respectively.
  88. k1 = coerce_numeric(keys[0], @semantic.keys[0], scope)
  89. k2 = coerce_numeric(keys[1], @semantic.keys[1], scope)
  90. [k1, k2].each_with_index { |k,i| bad_access_key_type(o, i, k, Integer) unless k.is_a?(Integer) }
  91. # Help confused Ruby do the right thing (it truncates to the right, but negative index + length can never overlap
  92. # the available range.
  93. k1 = k1 < 0 ? o.length + k1 : k1 # abs pos (negative is count from end)
  94. k2 = k2 < 0 ? o.length - k1 + k2 + 1 : k2 # abs length (negative k2 is length from pos to end count)
  95. # if k1 is outside, adjust to first position, and adjust length
  96. if k1 < 0
  97. k2 = k2 + k1
  98. k1 = 0
  99. end
  100. # Help ruby always return empty array when asking for a sub array
  101. result = o[ k1, k2 ]
  102. result.nil? ? [] : result
  103. else
  104. fail(Puppet::Pops::Issues::BAD_ARRAY_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
  105. end
  106. end
  107. # Evaluates <hsh>[] with support for one or more arguments. If more than one argument is used, the result
  108. # is an array with each lookup.
  109. # @note
  110. # Does not flatten its keys to enable looking up with a structure
  111. #
  112. def access_Hash(o, scope, keys)
  113. # Look up key in hash, if key is nil or :undef, try alternate form before giving up.
  114. # This makes :undef and nil "be the same key". (The alternative is to always only write one or the other
  115. # in all hashes - that is much harder to guarantee since the Hash is a regular Ruby hash.
  116. #
  117. result = keys.collect do |k|
  118. o.fetch(k) do |key|
  119. case key
  120. when nil
  121. o[:undef]
  122. when :undef
  123. o[:nil]
  124. else
  125. nil
  126. end
  127. end
  128. end
  129. case result.size
  130. when 0
  131. fail(Puppet::Pops::Issues::BAD_HASH_SLICE_ARITY, @semantic.left_expr, {:actual => keys.size})
  132. when 1
  133. result.pop
  134. else
  135. # remove nil elements and return
  136. result.compact!
  137. result
  138. end
  139. end
  140. # Ruby does not have an infinity constant. TODO: Consider having one constant in Puppet. Now it is in several places.
  141. INFINITY = 1.0 / 0.0
  142. def access_PEnumType(o, scope, keys)
  143. keys.flatten!
  144. assert_keys(keys, o, 1, INFINITY, String)
  145. Puppet::Pops::Types::TypeFactory.enum(*keys)
  146. end
  147. def access_PVariantType(o, scope, keys)
  148. keys.flatten!
  149. assert_keys(keys, o, 1, INFINITY, Puppet::Pops::Types::PAbstractType)
  150. Puppet::Pops::Types::TypeFactory.variant(*keys)
  151. end
  152. def access_PTupleType(o, scope, keys)
  153. keys.flatten!
  154. if TYPEFACTORY.is_range_parameter?(keys[-2]) && TYPEFACTORY.is_range_parameter?(keys[-1])
  155. size_type = TYPEFACTORY.range(keys[-2], keys[-1])
  156. keys = keys[0, keys.size - 2]
  157. elsif TYPEFACTORY.is_range_parameter?(keys[-1])
  158. size_type = TYPEFACTORY.range(keys[-1], :default)
  159. keys = keys[0, keys.size - 1]
  160. end
  161. assert_keys(keys, o, 1, INFINITY, Puppet::Pops::Types::PAbstractType)
  162. t = Puppet::Pops::Types::TypeFactory.tuple(*keys)
  163. # set size type, or nil for default (exactly 1)
  164. t.size_type = size_type
  165. t
  166. end
  167. def access_PCallableType(o, scope, keys)
  168. TYPEFACTORY.callable(*keys)
  169. end
  170. def access_PStructType(o, scope, keys)
  171. assert_keys(keys, o, 1, 1, Hash)
  172. TYPEFACTORY.struct(keys[0])
  173. end
  174. def access_PStringType(o, scope, keys)
  175. keys.flatten!
  176. case keys.size
  177. when 1
  178. size_t = collection_size_t(0, keys[0])
  179. when 2
  180. size_t = collection_size_t(0, keys[0], keys[1])
  181. else
  182. fail(Puppet::Pops::Issues::BAD_STRING_SLICE_ARITY, @semantic, {:actual => keys.size})
  183. end
  184. string_t = Puppet::Pops::Types::TypeFactory.string()
  185. string_t.size_type = size_t
  186. string_t
  187. end
  188. # Asserts type of each key and calls fail with BAD_TYPE_SPECIFICATION
  189. # @param keys [Array<Object>] the evaluated keys
  190. # @param o [Object] evaluated LHS reported as :base_type
  191. # @param min [Integer] the minimum number of keys (typically 1)
  192. # @param max [Numeric] the maximum number of keys (use same as min, specific number, or INFINITY)
  193. # @param allowed_classes [Class] a variable number of classes that each key must be an instance of (any)
  194. # @api private
  195. #
  196. def assert_keys(keys, o, min, max, *allowed_classes)
  197. size = keys.size
  198. unless size.between?(min, max || INFINITY)
  199. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, :base_type => o, :min=>1, :max => max, :actual => keys.size)
  200. end
  201. keys.each_with_index do |k, i|
  202. unless allowed_classes.any? {|clazz| k.is_a?(clazz) }
  203. bad_type_specialization_key_type(o, i, k, *allowed_classes)
  204. end
  205. end
  206. end
  207. def bad_access_key_type(lhs, key_index, actual, *expected_classes)
  208. fail(Puppet::Pops::Issues::BAD_SLICE_KEY_TYPE, @semantic.keys[key_index], {
  209. :left_value => lhs,
  210. :actual => bad_key_type_name(actual),
  211. :expected_classes => expected_classes
  212. })
  213. end
  214. def bad_key_type_name(actual)
  215. case actual
  216. when nil, :undef
  217. 'Undef'
  218. when :default
  219. 'Default'
  220. else
  221. actual.class.name
  222. end
  223. end
  224. def bad_type_specialization_key_type(type, key_index, actual, *expected_classes)
  225. label_provider = Puppet::Pops::Model::ModelLabelProvider.new()
  226. expected = expected_classes.map {|c| label_provider.label(c) }.join(' or ')
  227. fail(Puppet::Pops::Issues::BAD_TYPE_SPECIALIZATION, @semantic.keys[key_index], {
  228. :type => type,
  229. :message => "Cannot use #{bad_key_type_name(actual)} where #{expected} is expected"
  230. })
  231. end
  232. def access_PPatternType(o, scope, keys)
  233. keys.flatten!
  234. assert_keys(keys, o, 1, INFINITY, String, Regexp, Puppet::Pops::Types::PPatternType, Puppet::Pops::Types::PRegexpType)
  235. Puppet::Pops::Types::TypeFactory.pattern(*keys)
  236. end
  237. def access_POptionalType(o, scope, keys)
  238. keys.flatten!
  239. if keys.size == 1
  240. unless keys[0].is_a?(Puppet::Pops::Types::PAbstractType)
  241. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Optional-Type', :actual => keys[0].class})
  242. end
  243. result = Puppet::Pops::Types::POptionalType.new()
  244. result.optional_type = keys[0]
  245. result
  246. else
  247. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {:base_type => 'Optional-Type', :min => 1, :actual => keys.size})
  248. end
  249. end
  250. def access_PType(o, scope, keys)
  251. keys.flatten!
  252. if keys.size == 1
  253. unless keys[0].is_a?(Puppet::Pops::Types::PAbstractType)
  254. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Type-Type', :actual => keys[0].class})
  255. end
  256. result = Puppet::Pops::Types::PType.new()
  257. result.type = keys[0]
  258. result
  259. else
  260. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {:base_type => 'Type-Type', :min => 1, :actual => keys.size})
  261. end
  262. end
  263. def access_PRubyType(o, scope, keys)
  264. keys.flatten!
  265. assert_keys(keys, o, 1, 1, String)
  266. # create ruby type based on name of class, not inference of key's type
  267. Puppet::Pops::Types::TypeFactory.ruby_type(keys[0])
  268. end
  269. def access_PIntegerType(o, scope, keys)
  270. keys.flatten!
  271. unless keys.size.between?(1, 2)
  272. fail(Puppet::Pops::Issues::BAD_INTEGER_SLICE_ARITY, @semantic, {:actual => keys.size})
  273. end
  274. keys.each_with_index do |x, index|
  275. fail(Puppet::Pops::Issues::BAD_INTEGER_SLICE_TYPE, @semantic.keys[index],
  276. {:actual => x.class}) unless (x.is_a?(Integer) || x == :default)
  277. end
  278. ranged_integer = Puppet::Pops::Types::PIntegerType.new()
  279. from, to = keys
  280. ranged_integer.from = from == :default ? nil : from
  281. ranged_integer.to = to == :default ? nil : to
  282. ranged_integer
  283. end
  284. def access_PFloatType(o, scope, keys)
  285. keys.flatten!
  286. unless keys.size.between?(1, 2)
  287. fail(Puppet::Pops::Issues::BAD_FLOAT_SLICE_ARITY, @semantic, {:actual => keys.size})
  288. end
  289. keys.each_with_index do |x, index|
  290. fail(Puppet::Pops::Issues::BAD_FLOAT_SLICE_TYPE, @semantic.keys[index],
  291. {:actual => x.class}) unless (x.is_a?(Float) || x.is_a?(Integer) || x == :default)
  292. end
  293. ranged_float = Puppet::Pops::Types::PFloatType.new()
  294. from, to = keys
  295. ranged_float.from = from == :default || from.nil? ? nil : Float(from)
  296. ranged_float.to = to == :default || to.nil? ? nil : Float(to)
  297. ranged_float
  298. end
  299. # A Hash can create a new Hash type, one arg sets value type, two args sets key and value type in new type.
  300. # With 3 or 4 arguments, these are used to create a size constraint.
  301. # It is not possible to create a collection of Hash types directly.
  302. #
  303. def access_PHashType(o, scope, keys)
  304. keys.flatten!
  305. keys[0,2].each_with_index do |k, index|
  306. unless k.is_a?(Puppet::Pops::Types::PAbstractType)
  307. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[index], {:base_type => 'Hash-Type', :actual => k.class})
  308. end
  309. end
  310. case keys.size
  311. when 1
  312. result = Puppet::Pops::Types::PHashType.new()
  313. result.key_type = o.key_type.copy
  314. result.element_type = keys[0]
  315. result
  316. when 2
  317. result = Puppet::Pops::Types::PHashType.new()
  318. result.key_type = keys[0]
  319. result.element_type = keys[1]
  320. result
  321. when 3
  322. result = Puppet::Pops::Types::PHashType.new()
  323. result.key_type = keys[0]
  324. result.element_type = keys[1]
  325. size_t = collection_size_t(1, keys[2])
  326. result
  327. when 4
  328. result = Puppet::Pops::Types::PHashType.new()
  329. result.key_type = keys[0]
  330. result.element_type = keys[1]
  331. size_t = collection_size_t(1, keys[2], keys[3])
  332. result
  333. else
  334. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic, {
  335. :base_type => 'Hash-Type', :min => 1, :max => 4, :actual => keys.size
  336. })
  337. end
  338. result.size_type = size_t if size_t
  339. result
  340. end
  341. # CollectionType is parameterized with a range
  342. def access_PCollectionType(o, scope, keys)
  343. keys.flatten!
  344. case keys.size
  345. when 1
  346. size_t = collection_size_t(1, keys[0])
  347. when 2
  348. size_t = collection_size_t(1, keys[0], keys[1])
  349. else
  350. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic,
  351. {:base_type => 'Collection-Type', :min => 1, :max => 2, :actual => keys.size})
  352. end
  353. result = Puppet::Pops::Types::PCollectionType.new()
  354. result.size_type = size_t
  355. result
  356. end
  357. # An Array can create a new Array type. It is not possible to create a collection of Array types.
  358. #
  359. def access_PArrayType(o, scope, keys)
  360. keys.flatten!
  361. case keys.size
  362. when 1
  363. size_t = nil
  364. when 2
  365. size_t = collection_size_t(1, keys[1])
  366. when 3
  367. size_t = collection_size_t(1, keys[1], keys[2])
  368. else
  369. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, @semantic,
  370. {:base_type => 'Array-Type', :min => 1, :max => 3, :actual => keys.size})
  371. end
  372. unless keys[0].is_a?(Puppet::Pops::Types::PAbstractType)
  373. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_TYPE, @semantic.keys[0], {:base_type => 'Array-Type', :actual => keys[0].class})
  374. end
  375. result = Puppet::Pops::Types::PArrayType.new()
  376. result.element_type = keys[0]
  377. result.size_type = size_t
  378. result
  379. end
  380. # Produces an PIntegerType (range) given one or two keys.
  381. def collection_size_t(start_index, *keys)
  382. if keys.size == 1 && keys[0].is_a?(Puppet::Pops::Types::PIntegerType)
  383. keys[0].copy
  384. else
  385. keys.each_with_index do |x, index|
  386. fail(Puppet::Pops::Issues::BAD_COLLECTION_SLICE_TYPE, @semantic.keys[start_index + index],
  387. {:actual => x.class}) unless (x.is_a?(Integer) || x == :default)
  388. end
  389. ranged_integer = Puppet::Pops::Types::PIntegerType.new()
  390. from, to = keys
  391. ranged_integer.from = from == :default ? nil : from
  392. ranged_integer.to = to == :default ? nil : to
  393. ranged_integer
  394. end
  395. end
  396. # A Resource can create a new more specific Resource type, and/or an array of resource types
  397. # If the given type has title set, it can not be specified further.
  398. # @example
  399. # Resource[File] # => File
  400. # Resource[File, 'foo'] # => File[foo]
  401. # Resource[File. 'foo', 'bar'] # => [File[foo], File[bar]]
  402. # File['foo', 'bar'] # => [File[foo], File[bar]]
  403. # File['foo']['bar'] # => Value of the 'bar' parameter in the File['foo'] resource
  404. # Resource[File]['foo', 'bar'] # => [File[Foo], File[bar]]
  405. # Resource[File, 'foo', 'bar'] # => [File[foo], File[bar]]
  406. # Resource[File, 'foo']['bar'] # => Value of the 'bar' parameter in the File['foo'] resource
  407. #
  408. def access_PResourceType(o, scope, keys)
  409. blamed = keys.size == 0 ? @semantic : @semantic.keys[0]
  410. if keys.size == 0
  411. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed,
  412. :base_type => Puppet::Pops::Types::TypeCalculator.new().string(o), :min => 1, :max => -1, :actual => 0)
  413. end
  414. # Must know which concrete resource type to operate on in all cases.
  415. # It is not allowed to specify the type in an array arg - e.g. Resource[[File, 'foo']]
  416. # type_name is LHS type_name if set, else the first given arg
  417. type_name = o.type_name || keys.shift
  418. type_name = case type_name
  419. when Puppet::Pops::Types::PResourceType
  420. type_name.type_name
  421. when String
  422. type_name.downcase
  423. else
  424. # blame given left expression if it defined the type, else the first given key expression
  425. blame = o.type_name.nil? ? @semantic.keys[0] : @semantic.left_expr
  426. fail(Puppet::Pops::Issues::ILLEGAL_RESOURCE_SPECIALIZATION, blame, {:actual => type_name.class})
  427. end
  428. # The result is an array if multiple titles are given, or if titles are specified with an array
  429. # (possibly multiple arrays, and nested arrays).
  430. result_type_array = keys.size > 1 || keys[0].is_a?(Array)
  431. keys_orig_size = keys.size
  432. keys.flatten!
  433. keys.compact!
  434. # If given keys that were just a mix of empty/nil with empty array as a result.
  435. # As opposed to calling the function the wrong way (without any arguments), (configurable issue),
  436. # Return an empty array
  437. #
  438. if keys.empty? && keys_orig_size > 0
  439. optionally_fail(Puppet::Pops::Issues::EMPTY_RESOURCE_SPECIALIZATION, blamed)
  440. return result_type_array ? [] : nil
  441. end
  442. if !o.title.nil?
  443. # lookup resource and return one or more parameter values
  444. resource = find_resource(scope, o.type_name, o.title)
  445. unless resource
  446. fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE, @semantic, {:type_name => o.type_name, :title => o.title})
  447. end
  448. result = keys.map do |k|
  449. unless is_parameter_of_resource?(scope, resource, k)
  450. fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE_PARAMETER, @semantic,
  451. {:type_name => o.type_name, :title => o.title, :param_name=>k})
  452. end
  453. get_resource_parameter_value(scope, resource, k)
  454. end
  455. return result_type_array ? result : result.pop
  456. end
  457. keys = [:no_title] if keys.size < 1 # if there was only a type_name and it was consumed
  458. result = keys.each_with_index.map do |t, i|
  459. unless t.is_a?(String) || t == :no_title
  460. type_to_report = case t
  461. when nil, :undef
  462. 'Undef'
  463. when :default
  464. 'Default'
  465. else
  466. t.class.name
  467. end
  468. index = keys_orig_size != keys.size ? i+1 : i
  469. fail(Puppet::Pops::Issues::BAD_TYPE_SPECIALIZATION, @semantic.keys[index], {
  470. :type => o,
  471. :message => "Cannot use #{type_to_report} where String is expected"
  472. })
  473. end
  474. rtype = Puppet::Pops::Types::PResourceType.new()
  475. rtype.type_name = type_name
  476. rtype.title = (t == :no_title ? nil : t)
  477. rtype
  478. end
  479. # returns single type if request was for a single entity, else an array of types (possibly empty)
  480. return result_type_array ? result : result.pop
  481. end
  482. def access_PHostClassType(o, scope, keys)
  483. blamed = keys.size == 0 ? @semantic : @semantic.keys[0]
  484. keys_orig_size = keys.size
  485. # The result is an array if multiple classnames are given, or if classnames are specified with an array
  486. # (possibly multiple arrays, and nested arrays).
  487. result_type_array = keys.size > 1 || keys[0].is_a?(Array)
  488. keys.flatten!
  489. keys.compact!
  490. if keys_orig_size == 0
  491. fail(Puppet::Pops::Issues::BAD_TYPE_SLICE_ARITY, blamed,
  492. :base_type => Puppet::Pops::Types::TypeCalculator.new().string(o), :min => 1, :max => -1, :actual => 0)
  493. end
  494. # If given keys that were just a mix of empty/nil with empty array as a result.
  495. # As opposed to calling the function the wrong way (without any arguments), (configurable issue),
  496. # Return an empty array
  497. #
  498. if keys.empty? && keys_orig_size > 0
  499. optionally_fail(Puppet::Pops::Issues::EMPTY_RESOURCE_SPECIALIZATION, blamed)
  500. return result_type_array ? [] : nil
  501. end
  502. if ! o.class_name.nil?
  503. # lookup class resource and return one or more parameter values
  504. resource = find_resource(scope, 'class', o.class_name)
  505. unless resource
  506. fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE, @semantic, {:type_name => 'Class', :title => o.class_name})
  507. end
  508. result = keys.map do |k|
  509. unless is_parameter_of_resource?(scope, resource, k)
  510. fail(Puppet::Pops::Issues::UNKNOWN_RESOURCE_PARAMETER, @semantic,
  511. {:type_name => 'Class', :title => o.class_name, :param_name=>k})
  512. end
  513. get_resource_parameter_value(scope, resource, k)
  514. end
  515. return result_type_array ? result : result.pop
  516. end
  517. # The type argument may be a Resource Type - the Puppet Language allows a reference such as
  518. # Class[Foo], and this is interpreted as Class[Resource[Foo]] - which is ok as long as the resource
  519. # does not have a title. This should probably be deprecated.
  520. #
  521. result = keys.each_with_index.map do |c, i|
  522. ctype = Puppet::Pops::Types::PHostClassType.new()
  523. if c.is_a?(Puppet::Pops::Types::PResourceType) && !c.type_name.nil? && c.title.nil?
  524. # Remove leading '::' since all references are global, and 3x runtime does the wrong thing
  525. c = c.type_name.downcase.sub(/^::/, '')
  526. end
  527. unless c.is_a?(String)
  528. fail(Puppet::Pops::Issues::ILLEGAL_HOSTCLASS_NAME, @semantic.keys[i], {:name => c})
  529. end
  530. if c !~ Puppet::Pops::Patterns::NAME
  531. fail(Issues::ILLEGAL_NAME, @semantic.keys[i], {:name=>c})
  532. end
  533. ctype.class_name = c.downcase.sub(/^::/,'')
  534. ctype
  535. end
  536. # returns single type as type, else an array of types
  537. return result_type_array ? result : result.pop
  538. end
  539. end