rupkl 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/rupkl/node/amend_expression.rb +2 -2
- data/lib/rupkl/node/any.rb +15 -4
- data/lib/rupkl/node/base.rb +32 -2
- data/lib/rupkl/node/boolean.rb +26 -9
- data/lib/rupkl/node/collection.rb +176 -0
- data/lib/rupkl/node/data_size.rb +254 -0
- data/lib/rupkl/node/duration.rb +266 -0
- data/lib/rupkl/node/dynamic.rb +19 -15
- data/lib/rupkl/node/identifier.rb +5 -1
- data/lib/rupkl/node/if_expression.rb +45 -0
- data/lib/rupkl/node/intseq.rb +84 -0
- data/lib/rupkl/node/listing.rb +11 -4
- data/lib/rupkl/node/map.rb +120 -0
- data/lib/rupkl/node/mapping.rb +13 -6
- data/lib/rupkl/node/member_finder.rb +4 -10
- data/lib/rupkl/node/member_reference.rb +5 -3
- data/lib/rupkl/node/method_call.rb +2 -3
- data/lib/rupkl/node/method_definition.rb +74 -18
- data/lib/rupkl/node/node_common.rb +1 -1
- data/lib/rupkl/node/null.rb +1 -4
- data/lib/rupkl/node/number.rb +133 -45
- data/lib/rupkl/node/object.rb +322 -66
- data/lib/rupkl/node/operation.rb +123 -100
- data/lib/rupkl/node/pair.rb +58 -0
- data/lib/rupkl/node/pkl_module.rb +4 -4
- data/lib/rupkl/node/regex.rb +196 -0
- data/lib/rupkl/node/string.rb +155 -133
- data/lib/rupkl/node/struct_common.rb +70 -35
- data/lib/rupkl/node/value_common.rb +1 -5
- data/lib/rupkl/parser/expression.rb +43 -6
- data/lib/rupkl/parser/misc.rb +20 -0
- data/lib/rupkl/parser/object.rb +96 -13
- data/lib/rupkl/parser/pkl_class.rb +12 -5
- data/lib/rupkl/pkl_object.rb +2 -18
- data/lib/rupkl/version.rb +1 -1
- data/lib/rupkl.rb +10 -2
- metadata +17 -9
    
        data/lib/rupkl/node/string.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ module RuPkl | |
| 4 4 | 
             
              module Node
         | 
| 5 5 | 
             
                class String < Any
         | 
| 6 6 | 
             
                  include ValueCommon
         | 
| 7 | 
            +
                  include Operatable
         | 
| 7 8 |  | 
| 8 9 | 
             
                  uninstantiable_class
         | 
| 9 10 |  | 
| @@ -31,7 +32,7 @@ module RuPkl | |
| 31 32 | 
             
                    end
         | 
| 32 33 | 
             
                  end
         | 
| 33 34 |  | 
| 34 | 
            -
                  def copy(parent = nil)
         | 
| 35 | 
            +
                  def copy(parent = nil, position = @position)
         | 
| 35 36 | 
             
                    copied_portions =
         | 
| 36 37 | 
             
                      portions&.map do |portion|
         | 
| 37 38 | 
             
                        portion.is_a?(NodeCommon) && portion.copy || portion
         | 
| @@ -39,14 +40,6 @@ module RuPkl | |
| 39 40 | 
             
                    self.class.new(parent, nil, copied_portions, position)
         | 
| 40 41 | 
             
                  end
         | 
| 41 42 |  | 
| 42 | 
            -
                  def undefined_operator?(operator)
         | 
| 43 | 
            -
                    [:[], :==, :'!=', :+].none?(operator)
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                  def invalid_key_operand?(key)
         | 
| 47 | 
            -
                    !key.is_a?(Int)
         | 
| 48 | 
            -
                  end
         | 
| 49 | 
            -
             | 
| 50 43 | 
             
                  def find_by_key(key)
         | 
| 51 44 | 
             
                    index = key.value
         | 
| 52 45 | 
             
                    return nil unless (0...value.length).include?(index)
         | 
| @@ -54,6 +47,11 @@ module RuPkl | |
| 54 47 | 
             
                    self.class.new(parent, value[index], nil, position)
         | 
| 55 48 | 
             
                  end
         | 
| 56 49 |  | 
| 50 | 
            +
                  def b_op_add(r_operand, position)
         | 
| 51 | 
            +
                    result = value + r_operand.value
         | 
| 52 | 
            +
                    String.new(nil, result, nil, position)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 57 55 | 
             
                  define_builtin_property(:length) do
         | 
| 58 56 | 
             
                    Int.new(self, value.length, position)
         | 
| 59 57 | 
             
                  end
         | 
| @@ -104,231 +102,247 @@ module RuPkl | |
| 104 102 | 
             
                    raise EvaluationError.new(message, position)
         | 
| 105 103 | 
             
                  end
         | 
| 106 104 |  | 
| 107 | 
            -
                  define_builtin_method(:getOrNull, index: Int) do | | 
| 108 | 
            -
                     | 
| 109 | 
            -
             | 
| 105 | 
            +
                  define_builtin_method(:getOrNull, index: Int) do |args, parent, position|
         | 
| 106 | 
            +
                    index = args[:index].value
         | 
| 107 | 
            +
                    if (0...value.size).include?(index)
         | 
| 108 | 
            +
                      String.new(parent, value[index], nil, position)
         | 
| 110 109 | 
             
                    else
         | 
| 111 | 
            -
                      Null.new( | 
| 110 | 
            +
                      Null.new(parent, position)
         | 
| 112 111 | 
             
                    end
         | 
| 113 112 | 
             
                  end
         | 
| 114 113 |  | 
| 115 | 
            -
                  define_builtin_method( | 
| 116 | 
            -
                     | 
| 117 | 
            -
             | 
| 114 | 
            +
                  define_builtin_method(
         | 
| 115 | 
            +
                    :substring, start: Int, exclusive_end: Int
         | 
| 116 | 
            +
                  ) do |args, parent, position|
         | 
| 117 | 
            +
                    s = args[:start].value
         | 
| 118 | 
            +
                    e = args[:exclusive_end].value
         | 
| 119 | 
            +
                    check_range(s, 0, position)
         | 
| 120 | 
            +
                    check_range(e, s, position)
         | 
| 118 121 |  | 
| 119 | 
            -
                    String.new( | 
| 122 | 
            +
                    String.new(parent, value[s...e], nil, position)
         | 
| 120 123 | 
             
                  end
         | 
| 121 124 |  | 
| 122 | 
            -
                  define_builtin_method( | 
| 123 | 
            -
                     | 
| 124 | 
            -
             | 
| 125 | 
            +
                  define_builtin_method(
         | 
| 126 | 
            +
                    :substringOrNull, start: Int, exclusive_end: Int
         | 
| 127 | 
            +
                  ) do |args, parent, position|
         | 
| 128 | 
            +
                    s = args[:start].value
         | 
| 129 | 
            +
                    e = args[:exclusive_end].value
         | 
| 130 | 
            +
                    if inside_range?(s, 0) && inside_range?(e, s)
         | 
| 131 | 
            +
                      String.new(parent, value[s...e], nil, position)
         | 
| 125 132 | 
             
                    else
         | 
| 126 | 
            -
                      Null.new( | 
| 133 | 
            +
                      Null.new(parent, position)
         | 
| 127 134 | 
             
                    end
         | 
| 128 135 | 
             
                  end
         | 
| 129 136 |  | 
| 130 | 
            -
                  define_builtin_method(:repeat, count: Int) do | | 
| 131 | 
            -
                    check_positive_number(count)
         | 
| 137 | 
            +
                  define_builtin_method(:repeat, count: Int) do |args, parent, position|
         | 
| 138 | 
            +
                    check_positive_number(args[:count], position)
         | 
| 132 139 |  | 
| 133 | 
            -
                    result = value * count.value
         | 
| 134 | 
            -
                    String.new( | 
| 140 | 
            +
                    result = value * args[:count].value
         | 
| 141 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 135 142 | 
             
                  end
         | 
| 136 143 |  | 
| 137 | 
            -
                  define_builtin_method(:contains, pattern: String) do | | 
| 138 | 
            -
                    result = value.include?(pattern.value)
         | 
| 139 | 
            -
                    Boolean.new( | 
| 144 | 
            +
                  define_builtin_method(:contains, pattern: String) do |args, parent, position|
         | 
| 145 | 
            +
                    result = value.include?(args[:pattern].value)
         | 
| 146 | 
            +
                    Boolean.new(parent, result, position)
         | 
| 140 147 | 
             
                  end
         | 
| 141 148 |  | 
| 142 | 
            -
                  define_builtin_method(:startsWith, pattern: String) do | | 
| 143 | 
            -
                    result = value.start_with?(pattern.value)
         | 
| 144 | 
            -
                    Boolean.new( | 
| 149 | 
            +
                  define_builtin_method(:startsWith, pattern: String) do |args, parent, position|
         | 
| 150 | 
            +
                    result = value.start_with?(args[:pattern].value)
         | 
| 151 | 
            +
                    Boolean.new(parent, result, position)
         | 
| 145 152 | 
             
                  end
         | 
| 146 153 |  | 
| 147 | 
            -
                  define_builtin_method(:endsWith, pattern: String) do | | 
| 148 | 
            -
                    result = value.end_with?(pattern.value)
         | 
| 149 | 
            -
                    Boolean.new( | 
| 154 | 
            +
                  define_builtin_method(:endsWith, pattern: String) do |args, parent, position|
         | 
| 155 | 
            +
                    result = value.end_with?(args[:pattern].value)
         | 
| 156 | 
            +
                    Boolean.new(parent, result, position)
         | 
| 150 157 | 
             
                  end
         | 
| 151 158 |  | 
| 152 | 
            -
                  define_builtin_method(:indexOf, pattern: String) do | | 
| 153 | 
            -
                    index_of(:index, pattern) do
         | 
| 154 | 
            -
                      message = "\"#{pattern.value}\" does not occur in \"#{value}\""
         | 
| 159 | 
            +
                  define_builtin_method(:indexOf, pattern: String) do |args, parent, position|
         | 
| 160 | 
            +
                    index_of(:index, args[:pattern], parent, position) do
         | 
| 161 | 
            +
                      message = "\"#{args[:pattern].value}\" does not occur in \"#{value}\""
         | 
| 155 162 | 
             
                      raise EvaluationError.new(message, position)
         | 
| 156 163 | 
             
                    end
         | 
| 157 164 | 
             
                  end
         | 
| 158 165 |  | 
| 159 | 
            -
                  define_builtin_method(:indexOfOrNull, pattern: String) do | | 
| 160 | 
            -
                    index_of(:index, pattern) do
         | 
| 161 | 
            -
                      Null.new( | 
| 166 | 
            +
                  define_builtin_method(:indexOfOrNull, pattern: String) do |args, parent, position|
         | 
| 167 | 
            +
                    index_of(:index, args[:pattern], parent, position) do
         | 
| 168 | 
            +
                      Null.new(parent, position)
         | 
| 162 169 | 
             
                    end
         | 
| 163 170 | 
             
                  end
         | 
| 164 171 |  | 
| 165 | 
            -
                  define_builtin_method(:lastIndexOf, pattern: String) do | | 
| 166 | 
            -
                    index_of(:rindex, pattern) do
         | 
| 167 | 
            -
                      message = "\"#{pattern.value}\" does not occur in \"#{value}\""
         | 
| 172 | 
            +
                  define_builtin_method(:lastIndexOf, pattern: String) do |args, parent, position|
         | 
| 173 | 
            +
                    index_of(:rindex, args[:pattern], parent, position) do
         | 
| 174 | 
            +
                      message = "\"#{args[:pattern].value}\" does not occur in \"#{value}\""
         | 
| 168 175 | 
             
                      raise EvaluationError.new(message, position)
         | 
| 169 176 | 
             
                    end
         | 
| 170 177 | 
             
                  end
         | 
| 171 178 |  | 
| 172 | 
            -
                  define_builtin_method( | 
| 173 | 
            -
                     | 
| 174 | 
            -
             | 
| 179 | 
            +
                  define_builtin_method(
         | 
| 180 | 
            +
                    :lastIndexOfOrNull, pattern: String
         | 
| 181 | 
            +
                  ) do |args, parent, position|
         | 
| 182 | 
            +
                    index_of(:rindex, args[:pattern], parent, position) do
         | 
| 183 | 
            +
                      Null.new(parent, position)
         | 
| 175 184 | 
             
                    end
         | 
| 176 185 | 
             
                  end
         | 
| 177 186 |  | 
| 178 | 
            -
                  define_builtin_method(:take, n: Int) do | | 
| 179 | 
            -
                    check_positive_number(n)
         | 
| 187 | 
            +
                  define_builtin_method(:take, n: Int) do |args, parent, position|
         | 
| 188 | 
            +
                    check_positive_number(args[:n], position)
         | 
| 180 189 |  | 
| 181 | 
            -
                    result = value[0, n.value] || value
         | 
| 182 | 
            -
                    String.new( | 
| 190 | 
            +
                    result = value[0, args[:n].value] || value
         | 
| 191 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 183 192 | 
             
                  end
         | 
| 184 193 |  | 
| 185 | 
            -
                  define_builtin_method(:takeLast, n: Int) do | | 
| 186 | 
            -
                    check_positive_number(n)
         | 
| 194 | 
            +
                  define_builtin_method(:takeLast, n: Int) do |args, parent, position|
         | 
| 195 | 
            +
                    check_positive_number(args[:n], position)
         | 
| 187 196 |  | 
| 188 | 
            -
                    pos = value.size - n.value
         | 
| 197 | 
            +
                    pos = value.size - args[:n].value
         | 
| 189 198 | 
             
                    result = pos.negative? && value || value[pos..]
         | 
| 190 | 
            -
                    String.new( | 
| 199 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 191 200 | 
             
                  end
         | 
| 192 201 |  | 
| 193 | 
            -
                  define_builtin_method(:drop, n: Int) do | | 
| 194 | 
            -
                    check_positive_number(n)
         | 
| 202 | 
            +
                  define_builtin_method(:drop, n: Int) do |args, parent, position|
         | 
| 203 | 
            +
                    check_positive_number(args[:n], position)
         | 
| 195 204 |  | 
| 196 | 
            -
                    result = value[n.value..] || ''
         | 
| 197 | 
            -
                    String.new( | 
| 205 | 
            +
                    result = value[args[:n].value..] || ''
         | 
| 206 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 198 207 | 
             
                  end
         | 
| 199 208 |  | 
| 200 | 
            -
                  define_builtin_method(:dropLast, n: Int) do | | 
| 201 | 
            -
                    check_positive_number(n)
         | 
| 209 | 
            +
                  define_builtin_method(:dropLast, n: Int) do |args, parent, position|
         | 
| 210 | 
            +
                    check_positive_number(args[:n], position)
         | 
| 202 211 |  | 
| 203 | 
            -
                    length = value.size - n.value
         | 
| 212 | 
            +
                    length = value.size - args[:n].value
         | 
| 204 213 | 
             
                    result = length.negative? && '' || value[0, length]
         | 
| 205 | 
            -
                    String.new( | 
| 214 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 206 215 | 
             
                  end
         | 
| 207 216 |  | 
| 208 217 | 
             
                  define_builtin_method(
         | 
| 209 | 
            -
                    :replaceFirst,
         | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
                     | 
| 213 | 
            -
                    String.new(nil, result, nil, position)
         | 
| 218 | 
            +
                    :replaceFirst, pattern: String, replacement: String
         | 
| 219 | 
            +
                  ) do |args, parent, position|
         | 
| 220 | 
            +
                    result = value.sub(args[:pattern].value, args[:replacement].value)
         | 
| 221 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 214 222 | 
             
                  end
         | 
| 215 223 |  | 
| 216 224 | 
             
                  define_builtin_method(
         | 
| 217 | 
            -
                    :replaceLast,
         | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 225 | 
            +
                    :replaceLast, pattern: String, replacement: String
         | 
| 226 | 
            +
                  ) do |args, parent, position|
         | 
| 227 | 
            +
                    pattern = args[:pattern].value
         | 
| 228 | 
            +
                    replacement = args[:replacement].value
         | 
| 220 229 | 
             
                    result =
         | 
| 221 | 
            -
                      if (index = value.rindex(pattern | 
| 222 | 
            -
                        value.dup.tap { |s| s[index, replacement. | 
| 230 | 
            +
                      if (index = value.rindex(pattern))
         | 
| 231 | 
            +
                        value.dup.tap { |s| s[index, replacement.size] = replacement }
         | 
| 223 232 | 
             
                      else
         | 
| 224 233 | 
             
                        value
         | 
| 225 234 | 
             
                      end
         | 
| 226 | 
            -
                    String.new( | 
| 235 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 227 236 | 
             
                  end
         | 
| 228 237 |  | 
| 229 238 | 
             
                  define_builtin_method(
         | 
| 230 | 
            -
                    :replaceAll,
         | 
| 231 | 
            -
             | 
| 232 | 
            -
             | 
| 233 | 
            -
                     | 
| 234 | 
            -
                    String.new(nil, result, nil, position)
         | 
| 239 | 
            +
                    :replaceAll, pattern: String, replacement: String
         | 
| 240 | 
            +
                  ) do |args, parent, position|
         | 
| 241 | 
            +
                    result = value.gsub(args[:pattern].value, args[:replacement].value)
         | 
| 242 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 235 243 | 
             
                  end
         | 
| 236 244 |  | 
| 237 245 | 
             
                  define_builtin_method(
         | 
| 238 | 
            -
                    :replaceRange,
         | 
| 239 | 
            -
             | 
| 240 | 
            -
             | 
| 241 | 
            -
                     | 
| 242 | 
            -
                     | 
| 243 | 
            -
             | 
| 244 | 
            -
                     | 
| 245 | 
            -
                     | 
| 246 | 
            -
             | 
| 246 | 
            +
                    :replaceRange, start: Int, exclusive_end: Int, replacement: String
         | 
| 247 | 
            +
                  ) do |args, parent, position|
         | 
| 248 | 
            +
                    s = args[:start].value
         | 
| 249 | 
            +
                    e = args[:exclusive_end].value
         | 
| 250 | 
            +
                    r = args[:replacement].value
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                    check_range(s, 0, position)
         | 
| 253 | 
            +
                    check_range(e, s, position)
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                    result = value.dup.tap { _1[s...e] = r }
         | 
| 256 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 247 257 | 
             
                  end
         | 
| 248 258 |  | 
| 249 | 
            -
                  define_builtin_method(:toUpperCase) do
         | 
| 250 | 
            -
                    String.new( | 
| 259 | 
            +
                  define_builtin_method(:toUpperCase) do |_, parent, position|
         | 
| 260 | 
            +
                    String.new(parent, value.upcase, nil, position)
         | 
| 251 261 | 
             
                  end
         | 
| 252 262 |  | 
| 253 | 
            -
                  define_builtin_method(:toLowerCase) do
         | 
| 254 | 
            -
                    String.new( | 
| 263 | 
            +
                  define_builtin_method(:toLowerCase) do |_, parent, position|
         | 
| 264 | 
            +
                    String.new(parent, value.downcase, nil, position)
         | 
| 255 265 | 
             
                  end
         | 
| 256 266 |  | 
| 257 | 
            -
                  define_builtin_method(:reverse) do
         | 
| 258 | 
            -
                    String.new( | 
| 267 | 
            +
                  define_builtin_method(:reverse) do |_, parent, position|
         | 
| 268 | 
            +
                    String.new(parent, value.reverse, nil, position)
         | 
| 259 269 | 
             
                  end
         | 
| 260 270 |  | 
| 261 | 
            -
                  define_builtin_method(:trim) do
         | 
| 271 | 
            +
                  define_builtin_method(:trim) do |_, parent, position|
         | 
| 262 272 | 
             
                    pattern = /(?:\A\p{White_Space}+)|(?:\p{White_Space}+\z)/
         | 
| 263 | 
            -
                    String.new( | 
| 273 | 
            +
                    String.new(parent, value.gsub(pattern, ''), nil, position)
         | 
| 264 274 | 
             
                  end
         | 
| 265 275 |  | 
| 266 | 
            -
                  define_builtin_method(:trimStart) do
         | 
| 276 | 
            +
                  define_builtin_method(:trimStart) do |_, parent, position|
         | 
| 267 277 | 
             
                    pattern = /\A\p{White_Space}+/
         | 
| 268 | 
            -
                    String.new( | 
| 278 | 
            +
                    String.new(parent, value.sub(pattern, ''), nil, position)
         | 
| 269 279 | 
             
                  end
         | 
| 270 280 |  | 
| 271 | 
            -
                  define_builtin_method(:trimEnd) do
         | 
| 281 | 
            +
                  define_builtin_method(:trimEnd) do |_, parent, position|
         | 
| 272 282 | 
             
                    pattern = /\p{White_Space}+\z/
         | 
| 273 | 
            -
                    String.new( | 
| 283 | 
            +
                    String.new(parent, value.sub(pattern, ''), nil, position)
         | 
| 274 284 | 
             
                  end
         | 
| 275 285 |  | 
| 276 | 
            -
                  define_builtin_method( | 
| 277 | 
            -
                     | 
| 286 | 
            +
                  define_builtin_method(
         | 
| 287 | 
            +
                    :padStart, width: Int, char: String
         | 
| 288 | 
            +
                  ) do |args, parent, position|
         | 
| 289 | 
            +
                    pad(args[:width], args[:char], :pre, parent, position)
         | 
| 278 290 | 
             
                  end
         | 
| 279 291 |  | 
| 280 | 
            -
                  define_builtin_method( | 
| 281 | 
            -
                     | 
| 292 | 
            +
                  define_builtin_method(
         | 
| 293 | 
            +
                    :padEnd, width: Int, char: String
         | 
| 294 | 
            +
                  ) do |args, parent, position|
         | 
| 295 | 
            +
                    pad(args[:width], args[:char], :post, parent, position)
         | 
| 282 296 | 
             
                  end
         | 
| 283 297 |  | 
| 284 | 
            -
                  define_builtin_method(:capitalize) do
         | 
| 298 | 
            +
                  define_builtin_method(:capitalize) do |_, parent, position|
         | 
| 285 299 | 
             
                    result =
         | 
| 286 300 | 
             
                      value.empty? && value || value.dup.tap { |s| s[0] = s[0].upcase }
         | 
| 287 | 
            -
                    String.new( | 
| 301 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 288 302 | 
             
                  end
         | 
| 289 303 |  | 
| 290 | 
            -
                  define_builtin_method(:decapitalize) do
         | 
| 304 | 
            +
                  define_builtin_method(:decapitalize) do |_, parent, position|
         | 
| 291 305 | 
             
                    result =
         | 
| 292 306 | 
             
                      value.empty? && value || value.dup.tap { |s| s[0] = s[0].downcase }
         | 
| 293 | 
            -
                    String.new( | 
| 307 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 294 308 | 
             
                  end
         | 
| 295 309 |  | 
| 296 | 
            -
                  define_builtin_method(:toInt) do
         | 
| 297 | 
            -
                    to_int do
         | 
| 310 | 
            +
                  define_builtin_method(:toInt) do |_, parent, position|
         | 
| 311 | 
            +
                    to_int(parent, position) do
         | 
| 298 312 | 
             
                      message = "cannot parse string as Int \"#{value}\""
         | 
| 299 313 | 
             
                      raise EvaluationError.new(message, position)
         | 
| 300 314 | 
             
                    end
         | 
| 301 315 | 
             
                  end
         | 
| 302 316 |  | 
| 303 | 
            -
                  define_builtin_method(:toIntOrNull) do
         | 
| 304 | 
            -
                    to_int do
         | 
| 305 | 
            -
                      Null.new( | 
| 317 | 
            +
                  define_builtin_method(:toIntOrNull) do |_, parent, position|
         | 
| 318 | 
            +
                    to_int(parent, position) do
         | 
| 319 | 
            +
                      Null.new(parent, position)
         | 
| 306 320 | 
             
                    end
         | 
| 307 321 | 
             
                  end
         | 
| 308 322 |  | 
| 309 | 
            -
                  define_builtin_method(:toFloat) do
         | 
| 310 | 
            -
                    to_float do
         | 
| 323 | 
            +
                  define_builtin_method(:toFloat) do |_, parent, position|
         | 
| 324 | 
            +
                    to_float(parent, position) do
         | 
| 311 325 | 
             
                      message = "cannot parse string as Float \"#{value}\""
         | 
| 312 326 | 
             
                      raise EvaluationError.new(message, position)
         | 
| 313 327 | 
             
                    end
         | 
| 314 328 | 
             
                  end
         | 
| 315 329 |  | 
| 316 | 
            -
                  define_builtin_method(:toFloatOrNull) do
         | 
| 317 | 
            -
                    to_float do
         | 
| 318 | 
            -
                      Null.new( | 
| 330 | 
            +
                  define_builtin_method(:toFloatOrNull) do |_, parent, position|
         | 
| 331 | 
            +
                    to_float(parent, position) do
         | 
| 332 | 
            +
                      Null.new(parent, position)
         | 
| 319 333 | 
             
                    end
         | 
| 320 334 | 
             
                  end
         | 
| 321 335 |  | 
| 322 | 
            -
                  define_builtin_method(:toBoolean) do
         | 
| 323 | 
            -
                    to_boolean do
         | 
| 336 | 
            +
                  define_builtin_method(:toBoolean) do |_, parent, position|
         | 
| 337 | 
            +
                    to_boolean(parent, position) do
         | 
| 324 338 | 
             
                      message = "cannot parse string as Boolean \"#{value}\""
         | 
| 325 339 | 
             
                      raise EvaluationError.new(message, position)
         | 
| 326 340 | 
             
                    end
         | 
| 327 341 | 
             
                  end
         | 
| 328 342 |  | 
| 329 | 
            -
                  define_builtin_method(:toBooleanOrNull) do
         | 
| 330 | 
            -
                    to_boolean do
         | 
| 331 | 
            -
                      Null.new( | 
| 343 | 
            +
                  define_builtin_method(:toBooleanOrNull) do |_, parent, position|
         | 
| 344 | 
            +
                    to_boolean(parent, position) do
         | 
| 345 | 
            +
                      Null.new(parent, position)
         | 
| 332 346 | 
             
                    end
         | 
| 333 347 | 
             
                  end
         | 
| 334 348 |  | 
| @@ -359,7 +373,15 @@ module RuPkl | |
| 359 373 | 
             
                    string.gsub(/([\t\n\r"\\])/) { replace[_1] }
         | 
| 360 374 | 
             
                  end
         | 
| 361 375 |  | 
| 362 | 
            -
                  def  | 
| 376 | 
            +
                  def valid_key_operand?(key)
         | 
| 377 | 
            +
                    key.is_a?(Int)
         | 
| 378 | 
            +
                  end
         | 
| 379 | 
            +
             | 
| 380 | 
            +
                  def defined_operator?(operator)
         | 
| 381 | 
            +
                    [:[], :+].any?(operator)
         | 
| 382 | 
            +
                  end
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                  def check_range(index, start_index, position)
         | 
| 363 385 | 
             
                    return if inside_range?(index, start_index)
         | 
| 364 386 |  | 
| 365 387 | 
             
                    message = "index #{index} is out of range " \
         | 
| @@ -371,12 +393,12 @@ module RuPkl | |
| 371 393 | 
             
                    (start_index..value.size).include?(index)
         | 
| 372 394 | 
             
                  end
         | 
| 373 395 |  | 
| 374 | 
            -
                  def index_of(method, pattern)
         | 
| 396 | 
            +
                  def index_of(method, pattern, parent, position)
         | 
| 375 397 | 
             
                    result = value.__send__(method, pattern.value)
         | 
| 376 | 
            -
                    result && Int.new( | 
| 398 | 
            +
                    result && Int.new(parent, result, position) || yield
         | 
| 377 399 | 
             
                  end
         | 
| 378 400 |  | 
| 379 | 
            -
                  def pad(width, char, pre_post)
         | 
| 401 | 
            +
                  def pad(width, char, pre_post, parent, position)
         | 
| 380 402 | 
             
                    unless char.value.length == 1
         | 
| 381 403 | 
             
                      message = "expected a char, but got \"#{char.value}\""
         | 
| 382 404 | 
             
                      raise EvaluationError.new(message, position)
         | 
| @@ -385,7 +407,7 @@ module RuPkl | |
| 385 407 | 
             
                    result =
         | 
| 386 408 | 
             
                      pad_prefix_postfix(width, char, pre_post)
         | 
| 387 409 | 
             
                        .then { |pre, post| [pre, value, post].join }
         | 
| 388 | 
            -
                    String.new( | 
| 410 | 
            +
                    String.new(parent, result, nil, position)
         | 
| 389 411 | 
             
                  end
         | 
| 390 412 |  | 
| 391 413 | 
             
                  def pad_prefix_postfix(width, char, pre_post)
         | 
| @@ -399,13 +421,13 @@ module RuPkl | |
| 399 421 | 
             
                    end
         | 
| 400 422 | 
             
                  end
         | 
| 401 423 |  | 
| 402 | 
            -
                  def to_int
         | 
| 403 | 
            -
                    Int.new( | 
| 424 | 
            +
                  def to_int(parent, position)
         | 
| 425 | 
            +
                    Int.new(parent, Integer(remove_underscore_from_number(value), 10), position)
         | 
| 404 426 | 
             
                  rescue ArgumentError
         | 
| 405 427 | 
             
                    yield
         | 
| 406 428 | 
             
                  end
         | 
| 407 429 |  | 
| 408 | 
            -
                  def to_float
         | 
| 430 | 
            +
                  def to_float(parent, position)
         | 
| 409 431 | 
             
                    result =
         | 
| 410 432 | 
             
                      case value
         | 
| 411 433 | 
             
                      when 'NaN' then ::Float::NAN
         | 
| @@ -413,7 +435,7 @@ module RuPkl | |
| 413 435 | 
             
                      when '-Infinity' then -::Float::INFINITY
         | 
| 414 436 | 
             
                      else Float(remove_underscore_from_number(value))
         | 
| 415 437 | 
             
                      end
         | 
| 416 | 
            -
                    Float.new( | 
| 438 | 
            +
                    Float.new(parent, result, position)
         | 
| 417 439 | 
             
                  rescue ArgumentError
         | 
| 418 440 | 
             
                    yield
         | 
| 419 441 | 
             
                  end
         | 
| @@ -422,14 +444,14 @@ module RuPkl | |
| 422 444 | 
             
                    string.gsub(/(?:(?<=\d)|(?<=.[eE][+-]))_+/, '')
         | 
| 423 445 | 
             
                  end
         | 
| 424 446 |  | 
| 425 | 
            -
                  def to_boolean
         | 
| 447 | 
            +
                  def to_boolean(parent, position)
         | 
| 426 448 | 
             
                    result =
         | 
| 427 449 | 
             
                      case value
         | 
| 428 450 | 
             
                      when /\Atrue\z/i then true
         | 
| 429 451 | 
             
                      when /\Afalse\z/i then false
         | 
| 430 452 | 
             
                      else return yield
         | 
| 431 453 | 
             
                      end
         | 
| 432 | 
            -
                    Boolean.new( | 
| 454 | 
            +
                    Boolean.new(parent, result, position)
         | 
| 433 455 | 
             
                  end
         | 
| 434 456 | 
             
                end
         | 
| 435 457 | 
             
              end
         | 
| @@ -9,11 +9,30 @@ module RuPkl | |
| 9 9 | 
             
                  def initialize(parent, body, position)
         | 
| 10 10 | 
             
                    super
         | 
| 11 11 | 
             
                    @body = body
         | 
| 12 | 
            -
                    body && check_members
         | 
| 13 12 | 
             
                  end
         | 
| 14 13 |  | 
| 15 14 | 
             
                  attr_reader :body
         | 
| 16 15 |  | 
| 16 | 
            +
                  def properties(visibility: :object)
         | 
| 17 | 
            +
                    @body&.properties(visibility: visibility)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def entries
         | 
| 21 | 
            +
                    @body&.entries
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def elements
         | 
| 25 | 
            +
                    @body&.elements
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def members(visibility: :object)
         | 
| 29 | 
            +
                    @body&.members(visibility: visibility)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def items
         | 
| 33 | 
            +
                    @body&.items
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 17 36 | 
             
                  def evaluate(context = nil)
         | 
| 18 37 | 
             
                    do_evaluation(__method__, context, 1) do |c|
         | 
| 19 38 | 
             
                      @body&.evaluate(c)
         | 
| @@ -25,15 +44,10 @@ module RuPkl | |
| 25 44 | 
             
                    do_evaluation(__method__, context, 1) do |c|
         | 
| 26 45 | 
             
                      @body&.resolve_structure(c)
         | 
| 27 46 | 
             
                    end
         | 
| 47 | 
            +
                    @body && check_members
         | 
| 28 48 | 
             
                    self
         | 
| 29 49 | 
             
                  end
         | 
| 30 50 |  | 
| 31 | 
            -
                  def to_ruby(context = nil)
         | 
| 32 | 
            -
                    do_evaluation(__method__, context, 1, PklObject::SELF) do |c|
         | 
| 33 | 
            -
                      create_pkl_object(c)
         | 
| 34 | 
            -
                    end
         | 
| 35 | 
            -
                  end
         | 
| 36 | 
            -
             | 
| 37 51 | 
             
                  def to_pkl_string(context = nil)
         | 
| 38 52 | 
             
                    to_string(context)
         | 
| 39 53 | 
             
                  end
         | 
| @@ -52,50 +66,42 @@ module RuPkl | |
| 52 66 | 
             
                    true
         | 
| 53 67 | 
             
                  end
         | 
| 54 68 |  | 
| 55 | 
            -
                  def copy(parent = nil)
         | 
| 69 | 
            +
                  def copy(parent = nil, position = @position)
         | 
| 56 70 | 
             
                    self.class.new(parent, @body&.copy, position)
         | 
| 57 71 | 
             
                  end
         | 
| 58 72 |  | 
| 59 73 | 
             
                  def merge!(*bodies)
         | 
| 60 74 | 
             
                    return unless @body
         | 
| 61 75 |  | 
| 62 | 
            -
                    @body.merge!(*bodies)
         | 
| 76 | 
            +
                    @body.merge!(*bodies.compact)
         | 
| 63 77 | 
             
                    check_members
         | 
| 64 78 | 
             
                  end
         | 
| 65 79 |  | 
| 66 | 
            -
                  def undefined_operator?(operator)
         | 
| 67 | 
            -
                    [:[], :==, :'!='].none?(operator)
         | 
| 68 | 
            -
                  end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                  def coerce(_operator, r_operand)
         | 
| 71 | 
            -
                    [self, r_operand]
         | 
| 72 | 
            -
                  end
         | 
| 73 | 
            -
             | 
| 74 80 | 
             
                  private
         | 
| 75 81 |  | 
| 76 82 | 
             
                  def check_members
         | 
| 77 83 | 
             
                    message =
         | 
| 78 84 | 
             
                      if properties_not_allowed?
         | 
| 79 | 
            -
                        "'#{ | 
| 85 | 
            +
                        "'#{class_name}' cannot have a property"
         | 
| 80 86 | 
             
                      elsif entries_not_allowed?
         | 
| 81 | 
            -
                        "'#{ | 
| 87 | 
            +
                        "'#{class_name}' cannot have an entry"
         | 
| 82 88 | 
             
                      elsif elements_not_allowed?
         | 
| 83 | 
            -
                        "'#{ | 
| 89 | 
            +
                        "'#{class_name}' cannot have an element"
         | 
| 84 90 | 
             
                      end
         | 
| 85 91 | 
             
                    message &&
         | 
| 86 92 | 
             
                      (raise EvaluationError.new(message, position))
         | 
| 87 93 | 
             
                  end
         | 
| 88 94 |  | 
| 89 95 | 
             
                  def properties_not_allowed?
         | 
| 90 | 
            -
                     | 
| 96 | 
            +
                    properties.then { _1 && !_1.empty? }
         | 
| 91 97 | 
             
                  end
         | 
| 92 98 |  | 
| 93 99 | 
             
                  def entries_not_allowed?
         | 
| 94 | 
            -
                     | 
| 100 | 
            +
                    entries
         | 
| 95 101 | 
             
                  end
         | 
| 96 102 |  | 
| 97 103 | 
             
                  def elements_not_allowed?
         | 
| 98 | 
            -
                     | 
| 104 | 
            +
                    elements
         | 
| 99 105 | 
             
                  end
         | 
| 100 106 |  | 
| 101 107 | 
             
                  def do_evaluation(method, context, limit, ifreachlimit = nil)
         | 
| @@ -126,30 +132,55 @@ module RuPkl | |
| 126 132 | 
             
                    end
         | 
| 127 133 | 
             
                  end
         | 
| 128 134 |  | 
| 129 | 
            -
                   | 
| 135 | 
            +
                  SELF = Object.new.freeze
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                  def to_pkl_object(context)
         | 
| 138 | 
            +
                    to_ruby_object(context) do |properties, entries, elements|
         | 
| 139 | 
            +
                      PklObject.new do |object|
         | 
| 140 | 
            +
                        [
         | 
| 141 | 
            +
                          replace_self_hash(properties, object),
         | 
| 142 | 
            +
                          replace_self_hash(entries, object),
         | 
| 143 | 
            +
                          replace_self_array(elements, object)
         | 
| 144 | 
            +
                        ]
         | 
| 145 | 
            +
                      end
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                  def to_ruby_object(context)
         | 
| 150 | 
            +
                    do_evaluation(__method__, context, 1, SELF) do |c|
         | 
| 151 | 
            +
                      results = convert_members(c)
         | 
| 152 | 
            +
                      yield(*results)
         | 
| 153 | 
            +
                    end
         | 
| 154 | 
            +
                  end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  def convert_members(context)
         | 
| 130 157 | 
             
                    context.push_scope(@body).then do |c|
         | 
| 131 | 
            -
                       | 
| 132 | 
            -
             | 
| 133 | 
            -
                         | 
| 134 | 
            -
                         | 
| 135 | 
            -
             | 
| 158 | 
            +
                      to_ruby = proc { _1.to_ruby(c) }
         | 
| 159 | 
            +
                      [
         | 
| 160 | 
            +
                        properties&.to_h(&to_ruby),
         | 
| 161 | 
            +
                        entries&.to_h(&to_ruby),
         | 
| 162 | 
            +
                        elements&.map(&to_ruby)
         | 
| 163 | 
            +
                      ]
         | 
| 136 164 | 
             
                    end
         | 
| 137 165 | 
             
                  end
         | 
| 138 166 |  | 
| 139 | 
            -
                  def  | 
| 140 | 
            -
                     | 
| 167 | 
            +
                  def replace_self_hash(hash, replacement)
         | 
| 168 | 
            +
                    hash&.each do |key, value|
         | 
| 169 | 
            +
                      hash[key] = replacement if value.equal?(SELF)
         | 
| 170 | 
            +
                    end
         | 
| 141 171 | 
             
                  end
         | 
| 142 172 |  | 
| 143 | 
            -
                  def  | 
| 144 | 
            -
                     | 
| 173 | 
            +
                  def replace_self_array(array, replacement)
         | 
| 174 | 
            +
                    array&.each_with_index do |value, i|
         | 
| 175 | 
            +
                      array[i] = replacement if value.equal?(SELF)
         | 
| 176 | 
            +
                    end
         | 
| 145 177 | 
             
                  end
         | 
| 146 178 |  | 
| 147 179 | 
             
                  def to_string_object(context)
         | 
| 148 | 
            -
                    "new #{ | 
| 180 | 
            +
                    "new #{class_name} #{to_string_members(context)}"
         | 
| 149 181 | 
             
                  end
         | 
| 150 182 |  | 
| 151 183 | 
             
                  def to_string_members(context)
         | 
| 152 | 
            -
                    members = @body.members
         | 
| 153 184 | 
             
                    return '{}' if members.empty?
         | 
| 154 185 |  | 
| 155 186 | 
             
                    context.push_scope(@body).then do |c|
         | 
| @@ -159,6 +190,10 @@ module RuPkl | |
| 159 190 | 
             
                        .then { "{ #{_1} }" }
         | 
| 160 191 | 
             
                    end
         | 
| 161 192 | 
             
                  end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  def defined_operator?(operator)
         | 
| 195 | 
            +
                    operator == :[]
         | 
| 196 | 
            +
                  end
         | 
| 162 197 | 
             
                end
         | 
| 163 198 | 
             
              end
         | 
| 164 199 | 
             
            end
         |