cloudrail_si 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +3 -0
  3. data/examples/README.md +3 -0
  4. data/examples/simple/index.rb +11 -0
  5. data/lib/cloudrail_si.rb +41 -0
  6. data/lib/cloudrail_si/RedirectReceivers.rb +40 -0
  7. data/lib/cloudrail_si/Settings.rb +12 -0
  8. data/lib/cloudrail_si/errors/DetailErrors.rb +13 -0
  9. data/lib/cloudrail_si/errors/InternalError.rb +10 -0
  10. data/lib/cloudrail_si/errors/UserError.rb +11 -0
  11. data/lib/cloudrail_si/helpers/Helper.rb +151 -0
  12. data/lib/cloudrail_si/helpers/LimitedReadableStream.rb +55 -0
  13. data/lib/cloudrail_si/helpers/SequenceReadableStream.rb +59 -0
  14. data/lib/cloudrail_si/servicecode/InitSelfTest.rb +92 -0
  15. data/lib/cloudrail_si/servicecode/Interpreter.rb +213 -0
  16. data/lib/cloudrail_si/servicecode/Sandbox.rb +361 -0
  17. data/lib/cloudrail_si/servicecode/VarAddress.rb +11 -0
  18. data/lib/cloudrail_si/servicecode/commands/AwaitCodeRedirect.rb +48 -0
  19. data/lib/cloudrail_si/servicecode/commands/Break.rb +16 -0
  20. data/lib/cloudrail_si/servicecode/commands/CallFunc.rb +26 -0
  21. data/lib/cloudrail_si/servicecode/commands/Clone.rb +18 -0
  22. data/lib/cloudrail_si/servicecode/commands/Concat.rb +22 -0
  23. data/lib/cloudrail_si/servicecode/commands/Conditional.rb +27 -0
  24. data/lib/cloudrail_si/servicecode/commands/Create.rb +56 -0
  25. data/lib/cloudrail_si/servicecode/commands/Delete.rb +21 -0
  26. data/lib/cloudrail_si/servicecode/commands/Get.rb +25 -0
  27. data/lib/cloudrail_si/servicecode/commands/GetMimeType.rb +1005 -0
  28. data/lib/cloudrail_si/servicecode/commands/JumpRel.rb +18 -0
  29. data/lib/cloudrail_si/servicecode/commands/Pull.rb +34 -0
  30. data/lib/cloudrail_si/servicecode/commands/Push.rb +32 -0
  31. data/lib/cloudrail_si/servicecode/commands/Return.rb +16 -0
  32. data/lib/cloudrail_si/servicecode/commands/Set.rb +23 -0
  33. data/lib/cloudrail_si/servicecode/commands/Size.rb +26 -0
  34. data/lib/cloudrail_si/servicecode/commands/ThrowError.rb +17 -0
  35. data/lib/cloudrail_si/servicecode/commands/array/Uint8ToBase64.rb +25 -0
  36. data/lib/cloudrail_si/servicecode/commands/debug/Out.rb +24 -0
  37. data/lib/cloudrail_si/servicecode/commands/hash/md5.rb +29 -0
  38. data/lib/cloudrail_si/servicecode/commands/hash/sha1.rb +30 -0
  39. data/lib/cloudrail_si/servicecode/commands/http/RequestCall.rb +51 -0
  40. data/lib/cloudrail_si/servicecode/commands/json/Parse.rb +40 -0
  41. data/lib/cloudrail_si/servicecode/commands/json/Stringify.rb +21 -0
  42. data/lib/cloudrail_si/servicecode/commands/math/Floor.rb +27 -0
  43. data/lib/cloudrail_si/servicecode/commands/math/MathCombine.rb +35 -0
  44. data/lib/cloudrail_si/servicecode/commands/object/GetKeyArray.rb +21 -0
  45. data/lib/cloudrail_si/servicecode/commands/object/GetKeyValueArrays.rb +29 -0
  46. data/lib/cloudrail_si/servicecode/commands/stream/MakeJoinedStream.rb +38 -0
  47. data/lib/cloudrail_si/servicecode/commands/stream/MakeLimitedStream.rb +23 -0
  48. data/lib/cloudrail_si/servicecode/commands/stream/StreamToString.rb +25 -0
  49. data/lib/cloudrail_si/servicecode/commands/stream/StringToStream.rb +20 -0
  50. data/lib/cloudrail_si/servicecode/commands/string/Base64Encode.rb +42 -0
  51. data/lib/cloudrail_si/servicecode/commands/string/Format.rb +43 -0
  52. data/lib/cloudrail_si/servicecode/commands/string/IndexOf.rb +29 -0
  53. data/lib/cloudrail_si/servicecode/commands/string/LastIndexOf.rb +29 -0
  54. data/lib/cloudrail_si/servicecode/commands/string/Split.rb +29 -0
  55. data/lib/cloudrail_si/servicecode/commands/string/StringTransform.rb +29 -0
  56. data/lib/cloudrail_si/servicecode/commands/string/Substr.rb +30 -0
  57. data/lib/cloudrail_si/servicecode/commands/string/Substring.rb +30 -0
  58. data/lib/cloudrail_si/services/Facebook.rb +528 -0
  59. data/lib/cloudrail_si/services/FacebookPage.rb +310 -0
  60. data/lib/cloudrail_si/services/Foursquare.rb +314 -0
  61. data/lib/cloudrail_si/services/GitHub.rb +354 -0
  62. data/lib/cloudrail_si/services/GooglePlaces.rb +309 -0
  63. data/lib/cloudrail_si/services/GooglePlus.rb +367 -0
  64. data/lib/cloudrail_si/services/Instagram.rb +342 -0
  65. data/lib/cloudrail_si/services/LinkedIn.rb +363 -0
  66. data/lib/cloudrail_si/services/MicrosoftLive.rb +346 -0
  67. data/lib/cloudrail_si/services/Nexmo.rb +173 -0
  68. data/lib/cloudrail_si/services/Slack.rb +318 -0
  69. data/lib/cloudrail_si/services/Twilio.rb +173 -0
  70. data/lib/cloudrail_si/services/Twitter.rb +795 -0
  71. data/lib/cloudrail_si/services/Yahoo.rb +408 -0
  72. data/lib/cloudrail_si/services/Yelp.rb +389 -0
  73. data/lib/cloudrail_si/statistics/Statistics.rb +125 -0
  74. data/lib/cloudrail_si/types/Address.rb +9 -0
  75. data/lib/cloudrail_si/types/Charge.rb +33 -0
  76. data/lib/cloudrail_si/types/CloudMetaData.rb +19 -0
  77. data/lib/cloudrail_si/types/CreditCard.rb +76 -0
  78. data/lib/cloudrail_si/types/Date.rb +49 -0
  79. data/lib/cloudrail_si/types/DateOfBirth.rb +16 -0
  80. data/lib/cloudrail_si/types/Error.rb +21 -0
  81. data/lib/cloudrail_si/types/Location.rb +8 -0
  82. data/lib/cloudrail_si/types/POI.rb +17 -0
  83. data/lib/cloudrail_si/types/Refund.rb +25 -0
  84. data/lib/cloudrail_si/types/SandboxObject.rb +20 -0
  85. data/lib/cloudrail_si/types/SpaceAllocation.rb +13 -0
  86. data/lib/cloudrail_si/types/Subscription.rb +27 -0
  87. data/lib/cloudrail_si/types/SubscriptionPlan.rb +26 -0
  88. data/lib/cloudrail_si/types/Types.rb +43 -0
  89. data/lib/cloudrail_si/version.rb +3 -0
  90. metadata +205 -0
@@ -0,0 +1,213 @@
1
+ require 'json'
2
+
3
+ require_relative '../Helpers/helper'
4
+ require_relative '../servicecode/VarAddress'
5
+
6
+ require_relative './commands/AwaitCodeRedirect'
7
+ require_relative './commands/CallFunc'
8
+ require_relative './commands/Break'
9
+ require_relative './commands/Clone'
10
+ require_relative './commands/Concat'
11
+ require_relative './commands/Conditional'
12
+ require_relative './commands/Create'
13
+ require_relative './commands/Delete'
14
+ require_relative './commands/Get'
15
+ require_relative './commands/GetMimeType'
16
+ require_relative './commands/JumpRel'
17
+ require_relative './commands/Pull'
18
+ require_relative './commands/Push'
19
+ require_relative './commands/Return'
20
+ require_relative './commands/Set'
21
+ require_relative './commands/Size'
22
+ require_relative './commands/ThrowError'
23
+ require_relative './commands/array/Uint8ToBase64'
24
+ require_relative './commands/debug/Out'
25
+ require_relative './commands/hash/Sha1'
26
+ require_relative './commands/hash/Md5'
27
+ require_relative './commands/json/Parse'
28
+ require_relative './commands/json/Stringify'
29
+ require_relative './commands/http/RequestCall'
30
+ require_relative './commands/math/Floor'
31
+ require_relative './commands/math/MathCombine'
32
+ require_relative './commands/object/GetKeyArray'
33
+ require_relative './commands/object/GetKeyValueArrays'
34
+ require_relative './commands/string/Base64Encode'
35
+ require_relative './commands/string/Format'
36
+ require_relative './commands/string/IndexOf'
37
+ require_relative './commands/string/LastIndexOf'
38
+ require_relative './commands/string/Split'
39
+ require_relative './commands/string/StringTransform'
40
+ require_relative './commands/string/Substr'
41
+ require_relative './commands/string/Substring'
42
+ require_relative './commands/stream/StreamToString'
43
+ require_relative './commands/stream/StringToStream'
44
+ require_relative './commands/stream/MakeJoinedStream'
45
+ require_relative './commands/stream/MakeLimitedStream'
46
+
47
+ module CloudRailSi
48
+ module ServiceCode
49
+ class Interpreter
50
+ attr_reader :sandbox
51
+
52
+ def initialize(sandbox)
53
+ @sandbox = sandbox
54
+
55
+ @COMMAND_LIST = [
56
+ CallFunc.new,
57
+ Break.new,
58
+ Clone.new,
59
+ Create.new,
60
+ Delete.new,
61
+ Get.new,
62
+ JumpRel.new,
63
+ Pull.new,
64
+ Push.new,
65
+ Return.new,
66
+ Set.new,
67
+ Size.new,
68
+ Uint8ToBase64.new,
69
+ Sha1.new,
70
+ Md5.new,
71
+ Base64Encode.new,
72
+ StreamToString.new,
73
+ StringToStream.new,
74
+ MakeJoinedStream.new,
75
+ MakeLimitedStream.new,
76
+ RequestCall.new,
77
+ Out.new,
78
+ AwaitCodeRedirect.new,
79
+ GetMimeType.new,
80
+ Conditional.new('if==than', lambda { |c| (c == 0) }, false),
81
+ Conditional.new('if>=than', lambda { |c| (c >= 0) }, true),
82
+ Conditional.new('if>than', lambda { |c| (c > 0) }, true),
83
+ Conditional.new('if<=than', lambda { |c| (c <= 0) }, true),
84
+ Conditional.new('if<than', lambda { |c| (c < 0) }, true),
85
+ Conditional.new('if!=than', lambda { |c| (c != 0) }, false),
86
+ ThrowError.new,
87
+ Parse.new,
88
+ Stringify.new,
89
+ MathCombine.new('math.add', lambda { |elems| elems.reduce(0, :+) }),
90
+ MathCombine.new('math.multiply', lambda { |elems| elems.reduce(1, :*) }),
91
+ MathCombine.new('math.max', lambda { |elems | elems.max }),
92
+ MathCombine.new('math.min', lambda{ |elems | elems | elems.min }),
93
+ Floor.new,
94
+ GetKeyArray.new,
95
+ GetKeyValueArrays.new,
96
+ Concat.new,
97
+ Format.new,
98
+ IndexOf.new,
99
+ LastIndexOf.new,
100
+ Split.new,
101
+ Substr.new,
102
+ Substring.new,
103
+ StringTransform.new('string.lowerCase', lambda { |str| str.downcase }),
104
+ StringTransform.new('string.upperCase', lambda { |str| str.upcase }),
105
+ StringTransform.new('string.urlEncode', lambda { |str| URI::encode_www_form_component(str) }),
106
+ StringTransform.new('string.urlDecode', lambda { |str| URI::decode_www_form_component(str, Encoding::UTF_8) })
107
+ ]
108
+ @COMMANDS = {}
109
+ @COMMAND_LIST.each { |command|
110
+ @COMMANDS[command.get_identifier()] = command
111
+ }
112
+ end
113
+
114
+ def call_function(function_name, *parameters)
115
+ @sandbox.create_new_stack_level(function_name, 0)
116
+ Helper.add_all(@sandbox.current_parameters(), parameters)
117
+ if (@sandbox.current_function_code().nil?)
118
+ error_message = "Service code error: function #{function_name} not found"
119
+ raise Errors::InternalError.new(error_message)
120
+ end
121
+ return run_sync() # this was an async run
122
+ end
123
+
124
+ def call_function_sync(function_name, *parameters)
125
+ @sandbox.create_new_stack_level(function_name, 0)
126
+ Helper.add_all(@sandbox.current_parameters(), parameters)
127
+ if (@sandbox.current_function_code().nil?)
128
+ error_message = "Service code error: function #{function_name} not found"
129
+ raise Errors::InternalError.new(error_message)
130
+ end
131
+ return run_sync()
132
+ end
133
+
134
+ def run
135
+ raise Errors::InternalError.new('interpreter.run not supported.')
136
+ end
137
+
138
+ def run_sync
139
+ begin
140
+ while (@sandbox.current_service_code_line() < @sandbox.current_function_code().length && @sandbox.current_service_code_line() >= 0)
141
+ command = @sandbox.current_function_code()[@sandbox.current_service_code_line()]
142
+ Helper.log "\n\n\n#{command}"
143
+ if (@COMMANDS[command[0]].nil?)
144
+ raise Errors::InternalError.new("Unknown command: #{command[0]}")
145
+ end
146
+ command_parameters = Interpreter.decode_command_parameters(command)
147
+ @COMMANDS[command[0]].execute(@sandbox, command_parameters)
148
+ return if !@sandbox.thrown_error.nil?
149
+ @sandbox.increment_current_service_code_line(1)
150
+ while ((@sandbox.current_service_code_line() >= @sandbox.current_function_code().length ||
151
+ @sandbox.current_service_code_line() < 0) && @sandbox.code_function_name_stack.length > 1)
152
+ @sandbox.return_from_function()
153
+ end
154
+ end
155
+
156
+ rescue => e
157
+ raise e if (e.class.name == CloudRailSi::Errors::UserError)
158
+ error_message = 'Service code error in function ' + @sandbox.current_function_name() + ' at line ' + @sandbox.current_service_code_line().to_s + ' with message: ' + e.message
159
+ raise CloudRailSi::Errors::InternalError.new(error_message)
160
+ end
161
+ end
162
+
163
+ def self.decode_command_parameters(command)
164
+ command_parameters = command.clone[1..-1] # first param was function name
165
+ (0..command_parameters.length).each do |i|
166
+ if (Helper.is_string(command_parameters[i]))
167
+ if (command_parameters[i].index('$') === 0)
168
+ command_parameters[i] = VarAddress.new(command_parameters[i][1..-1])
169
+ elsif (command_parameters[i].index('\\$') === 0)
170
+ command_parameters[i] = command_parameters[i][1..-1]
171
+ end
172
+ end
173
+ end
174
+ return command_parameters
175
+ end
176
+
177
+ def get_parameter(idx)
178
+ @sandbox.get_parameter(idx, 0)
179
+ end
180
+
181
+ def save_as_string
182
+ @sandbox.peristent_storage.to_json
183
+ end
184
+
185
+ def load_as_string(saved_state)
186
+ @sandbox.persistent_storage = JSON.parse(saved_state)
187
+ end
188
+
189
+ def resume_function(function_name, *parameters)
190
+ if (@sandbox.parameters_stack.length === 0)
191
+ first_parameters = []
192
+ @sandbox.parameters_stack.push(first_parameters)
193
+ else
194
+ first_parameters = @sandbox.parameters_stack[0]
195
+ end
196
+ (0..parameters.length).each do |i|
197
+ if (Helper.is_object(parameters[i]))
198
+ m = parameters[i]
199
+ Helper.clear(m)
200
+ Helper.put_all(m, first_parameters[i])
201
+ else
202
+ if (i >= first_parameters.length)
203
+ first_parameters.push(parameters[i])
204
+ else
205
+ first_parameters[i] = parameters[i]
206
+ end
207
+ end
208
+ end
209
+ return run_sync()
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,361 @@
1
+ require_relative './Interpreter'
2
+ require_relative '../errors/InternalError'
3
+ require_relative '../helpers/Helper'
4
+
5
+ module CloudRailSi
6
+ module ServiceCode
7
+ class Sandbox
8
+ attr_reader :thrown_error
9
+ attr_reader :code_function_name_stack
10
+ attr_reader :local_variables_stack
11
+ attr_reader :instance_dependency_storage
12
+ attr_reader :code_line_stack
13
+
14
+ def is_sandbox
15
+ true
16
+ end
17
+
18
+ def initialize(service_code, persistent_storage, instance_dependency_storage)
19
+ @local_variables_stack = []
20
+ @parameters_stack = []
21
+ @code_function_name_stack = []
22
+ @code_line_stack = []
23
+ @persistent_storage = []
24
+ @service_code = service_code
25
+ @persistent_storage = persistent_storage
26
+ @instance_dependency_storage = instance_dependency_storage
27
+ @LIST_MAX_ADD_JUMP_ALLOWED = 32
28
+ @thrown_error = nil
29
+ end
30
+
31
+ def set_thrown_error(thrown_error)
32
+ Helper.debug
33
+ @thrown_error = thrown_error
34
+ end
35
+
36
+ def create_new_stack_level(function_name, code_line)
37
+ @local_variables_stack.push([])
38
+ @parameters_stack.push([])
39
+ @code_function_name_stack.push(function_name)
40
+ @code_line_stack.push(code_line)
41
+ end
42
+
43
+ def current_parameters
44
+ return nil if (@parameters_stack.length === 0)
45
+ @parameters_stack[-1]
46
+ end
47
+
48
+ def current_function_name
49
+ return nil if (@code_function_name_stack.length === 0)
50
+ @code_function_name_stack[-1]
51
+ end
52
+
53
+ def current_function_code
54
+ @service_code[current_function_name()]
55
+ end
56
+
57
+ def current_service_code_line
58
+ return -1 if (@code_line_stack.length === 0)
59
+ return @code_line_stack[-1]
60
+ end
61
+
62
+ def increment_current_service_code_line(amount)
63
+ @code_line_stack[-1] += amount if @code_line_stack.length
64
+ end
65
+ def return_from_function
66
+ return if (@code_function_name_stack.length <= 1)
67
+
68
+ call_function_command_parameters = Interpreter.decode_command_parameters(@service_code[@code_function_name_stack[-2]][@code_line_stack[-2]])
69
+
70
+ (0..call_function_command_parameters.length - 1).each do |i|
71
+ parameter_var = call_function_command_parameters[i]
72
+ if Helper.is_var_address(parameter_var)
73
+ value = @parameters_stack[-1][i - 1]
74
+ set_variable(parameter_var, value, -2)
75
+ end
76
+ end
77
+ @code_function_name_stack.pop()
78
+ @code_line_stack.pop()
79
+ @local_variables_stack.pop()
80
+ @parameters_stack.pop()
81
+ increment_current_service_code_line(1)
82
+ end
83
+ def set_variable(var_address, value, stacklevel=-1)
84
+ if Helper.is_var_address(var_address)
85
+ var_address_parts = decode_variable_address(var_address)
86
+ else
87
+ var_address_parts = var_address
88
+ end
89
+
90
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
91
+ var_idx = var_address_parts[1]
92
+ if (var_address_parts.length <= 2)
93
+ if (variables.length == var_idx)
94
+ variables.push(value)
95
+ elsif (variables.length > var_idx)
96
+ variables[var_idx] = value
97
+ elsif (variables.length + @LIST_MAX_ADD_JUMP_ALLOWED > var_idx)
98
+ (0..var_idx - variables.length + 1).each do |i|
99
+ variables.push(nil)
100
+ end
101
+ variables[var_idx] = value
102
+ else
103
+ raise Errors::InternalError.new("Could not decode variable #{var_address_parts.join(':')}")
104
+ end
105
+ return true
106
+ end
107
+
108
+ return set_entry(variables[var_idx], var_address_parts[2..-1], value)
109
+ end
110
+
111
+ def get_variable(var_address, stacklevel=-1, empty_is_null=false)
112
+ if Helper.is_var_address(var_address)
113
+ var_address_parts = decode_variable_address(var_address)
114
+ else
115
+ var_address_parts = var_address
116
+ end
117
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
118
+
119
+ return nil if (empty_is_null && var_address_parts[1] >= variables.length)
120
+
121
+ local_entry = variables[var_address_parts[1]]
122
+ return local_entry if (var_address_parts.length <= 2)
123
+ get_entry(local_entry, var_address_parts[2..-1], empty_is_null)
124
+ end
125
+
126
+ def delete_variable(var_address_parts, stacklevel=-1)
127
+ variables = get_stack_for_address_part(var_address_parts[0], stacklevel)
128
+ var_idx = var_address_parts[1]
129
+ if (var_address_parts.length <= 2)
130
+ variables[var_idx] = nil if (var_idx < variables.length)
131
+ return true
132
+ end
133
+ delete_entry(variables[var_idx], var_address_parts[2..-1])
134
+ end
135
+ def get_stack_for_address_part(part, stacklevel)
136
+ if (part == 'L')
137
+ variables = @local_variables_stack[stacklevel]
138
+ elsif (part == 'P')
139
+ variables = @parameters_stack[stacklevel]
140
+ elsif (part == 'S')
141
+ variables = @persistent_storage
142
+ else
143
+ raise Errors::InternalError.new("Could not attribute variable part #{part}")
144
+ end
145
+ return variables
146
+ end
147
+
148
+ def decode_variable_address(var_address)
149
+ dec_adr = []
150
+ adr = var_address.instance_variable_get(:@address_string)
151
+ Helper.assert(adr[0] != '$')
152
+ if (adr[0] < '0' || adr[0] > '9')
153
+ dec_adr.push(adr[0])
154
+ adr = adr[1..-1]
155
+ end
156
+ adr_parts = adr.split('.')
157
+ (0..adr_parts.length - 1).each do |i|
158
+ part = adr_parts[i]
159
+ if (Helper.is_number_string(part))
160
+ dec_adr.push(Integer(part))
161
+ else
162
+ dec_adr.push(part)
163
+ end
164
+ end
165
+ return dec_adr
166
+ end
167
+
168
+ def set_entry(container, var_address, value)
169
+ if (var_address.length > 1)
170
+ next_container = get_entry(container, var_address[0..-2], false)
171
+
172
+ return set_entry(next_container, var_address[1..-1], value)
173
+ end
174
+ var_address_part = var_address[0]
175
+
176
+ if (Helper.is_array(container))
177
+ if (Helper.is_number_string(var_address_part))
178
+ var_address_part = Integer(var_address_part)
179
+ end
180
+ if (!Helper.is_number(var_address_part) || var_address_part >= container.length)
181
+ raise Errors::InternalError.new('Invalid index while indexing into an array')
182
+ end
183
+ idx = var_address_part
184
+ list = container
185
+ if (list.length + @LIST_MAX_ADD_JUMP_ALLOWED <= idx)
186
+ (idx - list.length + 1).times do |i|
187
+ list.push(nil)
188
+ end
189
+ end
190
+ list[idx] = value
191
+ elsif (Helper.is_object(container))
192
+ if (!Helper.is_string(var_address_part))
193
+ var_address_part = var_address_part.to_s
194
+ end
195
+
196
+ #There are three ways to interpret an address; we try them all
197
+ begin
198
+ container.instance_variable_set('@' + var_address_part, value)
199
+ rescue
200
+ end
201
+ begin
202
+ container.send(Helper.to_snake_case(var_address_part) + "=", value)
203
+ rescue
204
+ end
205
+ begin
206
+ container[var_address_part] = value
207
+ rescue
208
+ end
209
+ elsif Helper.is_sandbox(container)
210
+ if (!Helper.is_string(var_address_part))
211
+ var_address_part = var_address_part.to_s
212
+ end
213
+ container.set(var_address_part, value)
214
+ end
215
+ return false
216
+ end
217
+ def get_entry(container, var_address, empty_is_null)
218
+ entry = ''
219
+ var_address_part = var_address[0]
220
+ if (Helper.is_array(container) || Helper.is_string(container))
221
+ if (Helper.is_number_string(var_address_part))
222
+ var_address_part = Integer(var_address_part)
223
+ end
224
+ if (!Helper.is_number(var_address_part))
225
+ var_address_part = 0 #TODO: for paypal, transactions is missing if the count is zero; this "fixes" it but might break other things.
226
+ # raise Errors::InternalError.new('Invalid index while indexing into an array or string')
227
+ end
228
+ if (!(empty_is_null && var_address_part >= container.length))
229
+ entry = container[var_address_part]
230
+ end
231
+ elsif (Helper.is_object(container))
232
+ if (!Helper.is_string(var_address_part))
233
+ var_address_part = var_address_part.to_s
234
+ end
235
+ if (container.nil? && (!empty_is_null))
236
+ entry = {}
237
+ else
238
+ begin
239
+ entry = container.instance_variable_get('@' + var_address_part) # will fail if var_address_part starts with a number; set to nil if doesn't exist
240
+ rescue
241
+ end
242
+ if !entry
243
+ begin
244
+ entry = container[var_address_part]
245
+ rescue
246
+ begin
247
+ entry = container.send(Helper.to_snake_case(var_address_part))
248
+ rescue
249
+ entry = {}
250
+ Helper.debug
251
+ end
252
+ end
253
+ end
254
+ end
255
+ elsif Helper.is_sandbox(container)
256
+ if (!Helper.is_string(var_address_part))
257
+ var_address_part = var_address_part.to_s
258
+ end
259
+ entry = container.get(var_address_part)
260
+ end
261
+ if (var_address.length > 1)
262
+ return get_entry( entry, var_address[1..-1], empty_is_null)
263
+ end
264
+ return entry
265
+ end
266
+ def delete_entry(container, var_address)
267
+ if (var_address.length > 1)
268
+ next_container = get_entry(container, var_address, false)
269
+ return delete_entry(next_container, var_address[1..-1])
270
+ end
271
+ var_address_part = var_address[0]
272
+ if (Helper.is_array(container))
273
+ if (Helper.is_number_string(var_address_part))
274
+ var_address_part = Integer(var_address_part)
275
+ end
276
+ if (!Helper.is_number(var_address_part) || var_address_part >= container.length)
277
+ raise Errors::InternalError.new('Invalid index while indexing into an array')
278
+ end
279
+ idx = var_address_part
280
+ list = container
281
+ if (idx < list.length)
282
+ list.delete_at(idx)
283
+ end
284
+ while (list.length && list[-1].nil?)
285
+ list.pop()
286
+ end
287
+ elsif (Helper.is_object(container))
288
+ var_address_part = var_address_part.to_s
289
+ container.delete(var_address_part)
290
+ elsif Helper.is_sandbox(container)
291
+ var_address_part = var_address_part.to_s
292
+ container.set(var_address_part, nil)
293
+ end
294
+ return false
295
+ end
296
+ def call_function(function_name, parameters)
297
+ create_new_stack_level(function_name, -1)
298
+ parameter_stack = current_parameters()
299
+ Helper.add_all(parameter_stack, parameters)
300
+ end
301
+ def compare_variables(a_obj, b_obj, command_id, type_check)
302
+ a_obj = Helper.resolve(self, a_obj, false)
303
+ b_obj = Helper.resolve(self, b_obj, false)
304
+ if (!type_check && (a_obj.nil? || b_obj.nil?))
305
+ return 0 if (a_obj.nil? && b_obj.nil?)
306
+ return -1
307
+ end
308
+
309
+ if ((a_obj.is_a? Numeric) && (b_obj.is_a? Numeric))
310
+ # doesn't matter if one is int and other is float
311
+ elsif (a_obj.class != b_obj.class)
312
+ Helper.debug
313
+ return -1 if !type_check
314
+ raise Errors::InternalError.new("Command #{command_id} compares arguments of different types")
315
+ end
316
+
317
+ return Helper.compare(a_obj, b_obj)
318
+ end
319
+ def save_state_to_string
320
+ savelist = []
321
+ savelist.push(@code_function_name_stack)
322
+ savelist.push(@code_line_stack)
323
+ savelist.push(@local_variables_stack)
324
+ savelist.push(@parameters_stack)
325
+ savelist.push(@persistent_storage)
326
+ as_json = savelist.to_json
327
+ # TODO: Add support for objects such as CustomDate
328
+
329
+ return as_json
330
+ end
331
+ def load_state_from_string(saved_state)
332
+ savelist = JSON.parse(saved_state)
333
+
334
+ # TODO: Add support for objects such as CustomDate
335
+ @code_function_name_stack = savelist[0]
336
+ @code_line_stack = savelist[1]
337
+ @local_variables_stack = savelist[2]
338
+ merge_stacks = lambda { |json_stack, stack|
339
+ (json_stack.length).times do |i|
340
+ if (i >= stack.length)
341
+ stack.push(json_stack[i])
342
+ else
343
+ stack[i] = json_stack[i]
344
+ end
345
+ end
346
+ }
347
+ json_parameters_stack = savelist[3]
348
+ json_persistent_storage = savelist[4]
349
+ merge_stacks(json_parameters_stack, @parameters_stack)
350
+ merge_stacks(json_persistent_storage, @persistent_storage)
351
+ end
352
+ def get_parameter(idx, stacklevel)
353
+ return nil if (@parameters_stack.length === 0 || stacklevel >= @parameters_stack.length || idx >= @parameters_stack[stacklevel].length)
354
+ @parameters_stack[stacklevel][idx]
355
+ end
356
+ def get_params_stack
357
+ @parameters_stack
358
+ end
359
+ end
360
+ end
361
+ end