Class: Peruby::Op::Element

Inherits:
Base
  • Object
show all
Defined in:
lib/peruby/op/element.rb

Overview

Array/hash access over package aggregates or references, with autovivification.

Instance Method Summary collapse

Methods inherited from Base

#argument_cells, #local_slot, #run_subroutine, #warning_directive?

Constructor Details

#initialize(container, key, kind, dereference, **options) ⇒ Element

Returns a new instance of Element.



7
8
9
10
11
12
13
14
# File 'lib/peruby/op/element.rb', line 7

def initialize(container, key, kind, dereference, **options)
  @container = container
  @key = key
  @kind = kind
  @dereference = dereference
  @slice = options.fetch(:slice, false)
  @key_value = options.fetch(:key_value, false)
end

Instance Method Details

#delete(env) ⇒ Object



81
82
83
84
# File 'lib/peruby/op/element.rb', line 81

def delete(env)
  container = aggregate(env)
  keys(env).map { |key| container.delete(key) }
end

#exists?(env) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
79
# File 'lib/peruby/op/element.rb', line 76

def exists?(env)
  container = aggregate(env)
  keys(env).all? { |key| container.exists?(key) }
end

#localize(env, stack) ⇒ Object

Raises:



86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/peruby/op/element.rb', line 86

def localize(env, stack)
  raise PerlError, "Can't localize slice" if @slice

  container = aggregate(env)
  key = @key.run(env, :scalar)
  key = key.get if key.respond_to?(:get)
  if @kind == :array
    stack.localize_array(container, Conv.to_num(key).to_i)
  else
    stack.localize_hash(container, Conv.to_str(key))
  end
end

#lvalue(env, context) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/peruby/op/element.rb', line 62

def lvalue(env, context)
  container = aggregate(env)
  unless @slice
    key = @key.run(env, :scalar)
    cell = slot(container, key.respond_to?(:get) ? key.get : key)
    return context == :list ? [cell] : cell
  end

  keys = @key.run(env, @slice ? :list : :scalar)
  keys = Array(keys).map { |key| key.respond_to?(:get) ? key.get : key }
  cells = keys.map { |key| slot(container, key) }
  context == :list ? cells : cells.last
end

#lvalue_callableObject



49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/peruby/op/element.rb', line 49

def lvalue_callable
  return ->(env, _key = nil) { lvalue(env, :list) } if @slice

  container = aggregate_callable
  kind = @kind
  lambda do |env, supplied_key = nil|
    key = supplied_key || @key.run(env, :scalar)
    key = key.value if key.respond_to?(:value)
    aggregate = container.call(env)
    kind == :array ? aggregate.slot(Conv.to_num(key).to_i) : aggregate.slot(Conv.to_str(key))
  end
end

#run(env, context) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/peruby/op/element.rb', line 16

def run(env, context)
  if @key_value && context == :list
    container = aggregate(env)
    return keys(env).flat_map { |key| [Scalar.new(Conv.to_str(key)), slot(container, key)] }
  end

  cells = lvalue(env, @slice ? :list : :scalar)
  return cells if context == :list && cells.is_a?(Array)

  cell = cells.is_a?(Array) ? cells.last : cells
  context == :list ? [cell] : cell&.get
end

#scalar_callableObject



40
41
42
43
44
45
46
47
# File 'lib/peruby/op/element.rb', line 40

def scalar_callable
  return unless !@slice && !@key_value

  key = @key.scalar_callable if @key.respond_to?(:scalar_callable)
  key ||= ->(env) { @key.run(env, :scalar) }
  lvalue = lvalue_callable
  ->(env) { lvalue.call(env, key.call(env))&.value }
end

#to_callableObject



29
30
31
32
33
34
35
36
37
38
# File 'lib/peruby/op/element.rb', line 29

def to_callable
  return super if @slice || @key_value

  key = @key.to_callable
  lvalue = lvalue_callable
  lambda do |env, context|
    cell = lvalue.call(env, key.call(env, :scalar))
    context == :list ? [cell] : cell&.value
  end
end