fable 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +30 -0
- data/.gitignore +57 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +21 -0
- data/README.md +2 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/test +8 -0
- data/fable.gemspec +34 -0
- data/fable.sublime-project +8 -0
- data/lib/fable.rb +49 -0
- data/lib/fable/call_stack.rb +351 -0
- data/lib/fable/choice.rb +31 -0
- data/lib/fable/choice_point.rb +65 -0
- data/lib/fable/container.rb +218 -0
- data/lib/fable/control_command.rb +156 -0
- data/lib/fable/debug_metadata.rb +13 -0
- data/lib/fable/divert.rb +100 -0
- data/lib/fable/glue.rb +7 -0
- data/lib/fable/ink_list.rb +425 -0
- data/lib/fable/list_definition.rb +44 -0
- data/lib/fable/list_definitions_origin.rb +35 -0
- data/lib/fable/native_function_call.rb +324 -0
- data/lib/fable/native_function_operations.rb +149 -0
- data/lib/fable/observer.rb +205 -0
- data/lib/fable/path.rb +186 -0
- data/lib/fable/pointer.rb +42 -0
- data/lib/fable/profiler.rb +287 -0
- data/lib/fable/push_pop_type.rb +11 -0
- data/lib/fable/runtime_object.rb +159 -0
- data/lib/fable/search_result.rb +20 -0
- data/lib/fable/serializer.rb +560 -0
- data/lib/fable/state_patch.rb +47 -0
- data/lib/fable/story.rb +1447 -0
- data/lib/fable/story_state.rb +915 -0
- data/lib/fable/tag.rb +14 -0
- data/lib/fable/value.rb +334 -0
- data/lib/fable/variable_assignment.rb +20 -0
- data/lib/fable/variable_reference.rb +38 -0
- data/lib/fable/variables_state.rb +327 -0
- data/lib/fable/version.rb +3 -0
- data/lib/fable/void.rb +4 -0
- data/zork_mode.rb +23 -0
- metadata +149 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Fable
|
2
|
+
class ListDefinition
|
3
|
+
attr_accessor :name, :items
|
4
|
+
|
5
|
+
# The main representation should be simple item names, rather than a
|
6
|
+
# RawListItem, since we mainly want to access items based on their
|
7
|
+
# simple name, since that's how they'll be most commonly requested
|
8
|
+
# from ink
|
9
|
+
attr_accessor :item_name_to_values
|
10
|
+
|
11
|
+
def items
|
12
|
+
if @items.nil?
|
13
|
+
@items = {}
|
14
|
+
@item_name_to_values.each do |key, value|
|
15
|
+
item = InkList::InkListItem.new(origin_name: name, item_name: key)
|
16
|
+
@items[item] = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
@items
|
20
|
+
end
|
21
|
+
|
22
|
+
def value_for_item(item)
|
23
|
+
return item_name_to_values[item.item_name] || 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def contains?(item)
|
27
|
+
return false if item.origin_name != self.name
|
28
|
+
return contains_item_with_name?(item.item_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
def contains_item_with_name?(item_name)
|
32
|
+
return item_name_to_values.has_key?(item_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def item_for_value(int_value)
|
36
|
+
return item_name_to_values.key(int_value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(name, items)
|
40
|
+
self.name = name
|
41
|
+
self.item_name_to_values = items
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Fable
|
2
|
+
class ListDefinitionsOrigin
|
3
|
+
attr_accessor :_lists, :all_unambiguous_list_value_cache
|
4
|
+
|
5
|
+
def lists
|
6
|
+
self._lists.map{|k,v| v}
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_list(name)
|
10
|
+
self._lists[name]
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(lists)
|
14
|
+
self._lists = {}
|
15
|
+
self.all_unambiguous_list_value_cache = {}
|
16
|
+
|
17
|
+
lists.each do |list|
|
18
|
+
self._lists[list.name] = list
|
19
|
+
|
20
|
+
list.items.each do |item, int_value|
|
21
|
+
list_value = ListValue.new(item, int_value)
|
22
|
+
|
23
|
+
# May be ambiguous, but compiler should've caught that,
|
24
|
+
# so we may be doing some replacement here, but that's okay
|
25
|
+
self.all_unambiguous_list_value_cache[item.item_name] = list_value
|
26
|
+
self.all_unambiguous_list_value_cache[item.full_name] = list_value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_single_item_list_with_name(name)
|
32
|
+
return all_unambiguous_list_value_cache[name]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
module Fable
|
2
|
+
class NativeFunctionCall < RuntimeObject
|
3
|
+
extend NativeFunctionOperations
|
4
|
+
|
5
|
+
FUNCTIONS = {
|
6
|
+
# native functions
|
7
|
+
ADDITION: "+",
|
8
|
+
SUBTRACTION: "-",
|
9
|
+
DIVIDE: "/",
|
10
|
+
MULTIPLY: "*",
|
11
|
+
MODULO: "%",
|
12
|
+
NEGATE: "_",
|
13
|
+
|
14
|
+
EQUALS: "==",
|
15
|
+
GREATER_THAN: ">",
|
16
|
+
LESS_THAN: "<",
|
17
|
+
GREATER_THAN_OR_EQUAL_TO: ">=",
|
18
|
+
LESS_THAN_OR_EQUAL_TO: "<=",
|
19
|
+
NOT_EQUAL: "!=",
|
20
|
+
NOT: "!",
|
21
|
+
|
22
|
+
|
23
|
+
AND: "&&",
|
24
|
+
OR: "||",
|
25
|
+
|
26
|
+
MIN: "MIN",
|
27
|
+
MAX: "MAX",
|
28
|
+
|
29
|
+
POWER: "POW",
|
30
|
+
FLOOR: "FLOOR",
|
31
|
+
CEILING: "CEILING",
|
32
|
+
INT_VALUE: "INT",
|
33
|
+
FLOAT_VALUE: "FLOAT",
|
34
|
+
|
35
|
+
HAS: "?",
|
36
|
+
HAS_NOT: "!?",
|
37
|
+
INTERSECTION: "^",
|
38
|
+
|
39
|
+
LIST_MINIMUM: "LIST_MIN",
|
40
|
+
LIST_MAXIMUM: "LIST_MAX",
|
41
|
+
LIST_ALL: "LIST_ALL",
|
42
|
+
LIST_COUNT: "LIST_COUNT",
|
43
|
+
VALUE_OF_LIST: "LIST_VALUE",
|
44
|
+
LIST_INVERT: "LIST_INVERT",
|
45
|
+
}.freeze
|
46
|
+
|
47
|
+
NUMBER_OF_PARAMETERS = {
|
48
|
+
ADDITION: 2,
|
49
|
+
SUBTRACTION: 2,
|
50
|
+
DIVIDE: 2,
|
51
|
+
MULTIPLY: 2,
|
52
|
+
MODULO: 2,
|
53
|
+
NEGATE: 1,
|
54
|
+
|
55
|
+
EQUALS: 2,
|
56
|
+
GREATER_THAN: 2,
|
57
|
+
LESS_THAN: 2,
|
58
|
+
GREATER_THAN_OR_EQUAL_TO: 2,
|
59
|
+
LESS_THAN_OR_EQUAL_TO: 2,
|
60
|
+
NOT_EQUAL: 2,
|
61
|
+
NOT: 1,
|
62
|
+
|
63
|
+
|
64
|
+
AND: 2,
|
65
|
+
OR: 2,
|
66
|
+
|
67
|
+
MIN: 2,
|
68
|
+
MAX: 2,
|
69
|
+
|
70
|
+
POWER: 2,
|
71
|
+
FLOOR: 1,
|
72
|
+
CEILING: 1,
|
73
|
+
INT_VALUE: 1,
|
74
|
+
FLOAT_VALUE: 1,
|
75
|
+
|
76
|
+
HAS: 2,
|
77
|
+
HAS_NOT: 2,
|
78
|
+
INTERSECTION: 2,
|
79
|
+
|
80
|
+
LIST_MINIMUM: 1,
|
81
|
+
LIST_MAXIMUM: 1,
|
82
|
+
LIST_ALL: 1,
|
83
|
+
LIST_COUNT: 1,
|
84
|
+
VALUE_OF_LIST: 1,
|
85
|
+
LIST_INVERT: 1,
|
86
|
+
}.freeze
|
87
|
+
|
88
|
+
LOOKUP = FUNCTIONS.invert.freeze
|
89
|
+
|
90
|
+
attr_accessor :name, :number_of_parameters
|
91
|
+
|
92
|
+
def self.is_native_function?(value)
|
93
|
+
LOOKUP.has_key?(value)
|
94
|
+
end
|
95
|
+
|
96
|
+
def initialize(function_symbol)
|
97
|
+
super()
|
98
|
+
self.name = LOOKUP[function_symbol]
|
99
|
+
self.number_of_parameters = NUMBER_OF_PARAMETERS[self.name]
|
100
|
+
end
|
101
|
+
|
102
|
+
def call!(parameters)
|
103
|
+
if parameters.size != self.number_of_parameters
|
104
|
+
raise StoryError, "Unexpected number of parameters"
|
105
|
+
end
|
106
|
+
|
107
|
+
has_list = false
|
108
|
+
|
109
|
+
parameters.each do |parameter|
|
110
|
+
case parameter
|
111
|
+
when Void
|
112
|
+
raise StoryError, "Attempting to perform operation on a void value. Did you forget to 'return' a value from a function you called here?"
|
113
|
+
when ListValue
|
114
|
+
has_list = true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Binary operations on lists are treated outside of the standard coercion rules
|
119
|
+
if parameters.size == 2 && has_list
|
120
|
+
return call_binary_list_operation(parameters)
|
121
|
+
end
|
122
|
+
|
123
|
+
coerced_parameters = coerce_values_to_single_type(parameters)
|
124
|
+
|
125
|
+
return underlying_function_call(coerced_parameters)
|
126
|
+
end
|
127
|
+
|
128
|
+
def underlying_function_call(parameters)
|
129
|
+
parameter_1 = parameters.first
|
130
|
+
value_type = parameter_1.class
|
131
|
+
|
132
|
+
if parameters.size > 2
|
133
|
+
raise Error, "Unexpected number of parameters to NativeFunctionCall: #{parameters.size}"
|
134
|
+
end
|
135
|
+
|
136
|
+
# if !can_perform_function_on?(value_type)
|
137
|
+
# raise Error, "Cannot perform operation '#{self.name}' on #{value_type}"
|
138
|
+
# end
|
139
|
+
|
140
|
+
# Binary function
|
141
|
+
if parameters.size == 2
|
142
|
+
parameter_2 = parameters.last
|
143
|
+
result = run_operation(parameter_1.value, parameter_2.value)
|
144
|
+
|
145
|
+
return Value.create(result)
|
146
|
+
# Unary Function
|
147
|
+
else
|
148
|
+
result = run_operation(parameter_1.value)
|
149
|
+
return Value.create(result)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def call_binary_list_operation(parameters)
|
154
|
+
value_1 = parameters[0]
|
155
|
+
value_2 = parameters[1]
|
156
|
+
|
157
|
+
# List-Int addition/subtraction returns a List (eg: "alpha" + 1 = "beta")
|
158
|
+
if (name == :ADDITION || name == :SUBTRACTION) && value_1.is_a?(ListValue) && value_2.is_a?(IntValue)
|
159
|
+
return call_list_increment_operation(parameters)
|
160
|
+
end
|
161
|
+
|
162
|
+
# And/or with any other types required coercion to bool (int)
|
163
|
+
if (name == :AND || :OR) && (!value_1.is_a?(ListValue) || !value_2.is_a?(ListValue))
|
164
|
+
value_1_as_boolean = value_1.truthy? ? 1 : 0
|
165
|
+
value_2_as_boolean = value_2.truthy? ? 1 : 0
|
166
|
+
|
167
|
+
result = run_operation(value_1_as_boolean, value_2_as_boolean)
|
168
|
+
return IntValue.new(result)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Normal (list X list) operation
|
172
|
+
if value_1.is_a?(ListValue) && value_2.is_a?(ListValue)
|
173
|
+
if name == :HAS || name == :HAS_NOT
|
174
|
+
return run_operation(value_1.value, value_2.value)
|
175
|
+
else
|
176
|
+
result = run_operation(value_1.value, value_2.value)
|
177
|
+
return ListValue.new(result)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
raise Error, "Can not call '#{name}' operation on '#{value_1.class}' and '#{value_2.class}'"
|
182
|
+
end
|
183
|
+
|
184
|
+
def call_list_increment_operation(parameters)
|
185
|
+
list_value = parameters[0]
|
186
|
+
int_value = parameters[1]
|
187
|
+
|
188
|
+
result_list = InkList.new
|
189
|
+
|
190
|
+
list_value.value.items.each do |list_item, list_item_value|
|
191
|
+
target_integer = run_operation(list_item_value, int_value.value)
|
192
|
+
|
193
|
+
# Find this item's origin
|
194
|
+
item_origin = list_value.value.origins.find{|origin| origin.name == list_item.origin_name }
|
195
|
+
|
196
|
+
if !item_origin.nil?
|
197
|
+
incremented_item = item_origin.item_for_value(target_integer)
|
198
|
+
if !incremented_item.nil?
|
199
|
+
result_list.add(incremented_item, target_integer)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
return ListValue.new(result_list)
|
205
|
+
end
|
206
|
+
|
207
|
+
def coerce_values_to_single_type(parameters)
|
208
|
+
given_types = parameters.map(&:class)
|
209
|
+
special_case_list = parameters.find{|x| x.is_a?(ListValue) }
|
210
|
+
|
211
|
+
# Find out what the output type is; "higher-level" types infect both
|
212
|
+
# so that binary operations use the same type on both sides
|
213
|
+
# (eg: binary operation of int & float causes the int to be casted as a float)
|
214
|
+
value_type = ([IntValue] + given_types).max{|a,b| OrderedValueTypes[a] <=> OrderedValueTypes[b] }
|
215
|
+
|
216
|
+
# Coerce to this chosen type
|
217
|
+
parameters_out = []
|
218
|
+
|
219
|
+
# Special case: Coercing Ints to Lists
|
220
|
+
# We have to do it early when we have both parameters
|
221
|
+
# to hand, so that we can make use of the list's origin
|
222
|
+
if value_type == ListValue
|
223
|
+
parameters.each do |parameter|
|
224
|
+
if parameter.is_a?(ListValue)
|
225
|
+
parameters_out << parameter
|
226
|
+
elsif parameter.is_a?(IntValue)
|
227
|
+
int_value = parameter.value
|
228
|
+
list = special_case_list.value.origin_of_max_item
|
229
|
+
|
230
|
+
item = list.item_for_value(int_value)
|
231
|
+
|
232
|
+
if !item.nil?
|
233
|
+
parameters_out << ListValue.new(item, int_value)
|
234
|
+
else
|
235
|
+
raise Error, "Could not find List item with the value '#{int_value}' in #{list.name}"
|
236
|
+
end
|
237
|
+
else
|
238
|
+
raise Error, "Cannot mix Lists and #{parameter.class} values in this operation"
|
239
|
+
end
|
240
|
+
end
|
241
|
+
# Normal coercing, with standard casting
|
242
|
+
else
|
243
|
+
parameters.each do |parameter|
|
244
|
+
parameters_out << parameter.cast(value_type)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
return parameters_out
|
249
|
+
end
|
250
|
+
|
251
|
+
def to_s
|
252
|
+
"Native '#{name}'"
|
253
|
+
end
|
254
|
+
|
255
|
+
protected
|
256
|
+
|
257
|
+
def run_operation(*parameters)
|
258
|
+
case name
|
259
|
+
when :ADDITION
|
260
|
+
return self.class.addition(parameters[1], parameters[0])
|
261
|
+
when :SUBTRACTION
|
262
|
+
return self.class.subtraction(parameters[1], parameters[0])
|
263
|
+
when :DIVIDE
|
264
|
+
return self.class.divide(parameters[1], parameters[0])
|
265
|
+
when :MULTIPLY
|
266
|
+
return self.class.multiply(parameters[1], parameters[0])
|
267
|
+
when :MODULO
|
268
|
+
return self.class.modulo(parameters[1], parameters[0])
|
269
|
+
when :NEGATE
|
270
|
+
return self.class.negate(parameter[0])
|
271
|
+
when :EQUALS
|
272
|
+
return self.class.equal(parameters[1], parameters[0])
|
273
|
+
when :GREATER_THAN
|
274
|
+
return self.class.greater(parameters[1], parameters[0])
|
275
|
+
when :LESS_THAN
|
276
|
+
return self.class.less(parameters[1], parameters[0])
|
277
|
+
when :GREATER_THAN_OR_EQUAL_TO
|
278
|
+
return self.class.greater_than_or_equal(parameters[1], parameters[0])
|
279
|
+
when :LESS_THAN_OR_EQUAL_TO
|
280
|
+
return self.class.less_than_or_equal(parameters[1], parameters[0])
|
281
|
+
when :NOT_EQUAL
|
282
|
+
return self.class.not_equal(parameters[1], parameters[0])
|
283
|
+
when :NOT
|
284
|
+
return self.class.not(parameters[0])
|
285
|
+
when :AND
|
286
|
+
return self.class.and(parameters[1], parameters[0])
|
287
|
+
when :OR
|
288
|
+
return self.class.or(parameters[1], parameters[0])
|
289
|
+
when :MIN
|
290
|
+
return self.class.min(parameters[1], parameters[0])
|
291
|
+
when :MAX
|
292
|
+
return self.class.max(parameters[1], parameters[0])
|
293
|
+
when :POWER
|
294
|
+
return self.class.pow(parameters[1], parameters[0])
|
295
|
+
when :FLOOR
|
296
|
+
return self.class.floor(parameters[0])
|
297
|
+
when :CEILING
|
298
|
+
return self.class.ceiling(parameters[0])
|
299
|
+
when :INT_VALUE
|
300
|
+
return self.class.int_value(parameters[0])
|
301
|
+
when :FLOAT_VALUE
|
302
|
+
return self.class.float_value(parameters[0])
|
303
|
+
when :HAS
|
304
|
+
return self.class.has(parameters[1], parameters[0])
|
305
|
+
when :HAS_NOT
|
306
|
+
return self.class.has_not(parameters[1], parameters[0])
|
307
|
+
when :INTERSECTION
|
308
|
+
return self.class.intersection(parameters[1], parameters[0])
|
309
|
+
when :LIST_MINIMUM
|
310
|
+
return self.class.list_min(parameters[0])
|
311
|
+
when :LIST_MAXIMUM
|
312
|
+
return self.class.list_max(parameters[0])
|
313
|
+
when :LIST_ALL
|
314
|
+
return self.class.all(parameters[0])
|
315
|
+
when :LIST_COUNT
|
316
|
+
return self.class.count(parameters[0])
|
317
|
+
when :VALUE_OF_LIST
|
318
|
+
return self.class.value_of_list(parameters[0])
|
319
|
+
when :LIST_INVERT
|
320
|
+
return self.class.invert(parameters[0])
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Fable
|
2
|
+
module NativeFunctionOperations
|
3
|
+
def addition(x, y)
|
4
|
+
return x + y
|
5
|
+
end
|
6
|
+
|
7
|
+
def subtraction(x,y)
|
8
|
+
return x - y
|
9
|
+
end
|
10
|
+
|
11
|
+
def multiply(x,y)
|
12
|
+
return x * y
|
13
|
+
end
|
14
|
+
|
15
|
+
def divide(x,y)
|
16
|
+
x / y
|
17
|
+
end
|
18
|
+
|
19
|
+
def modulo(x,y)
|
20
|
+
return x % y
|
21
|
+
end
|
22
|
+
|
23
|
+
def negate(x)
|
24
|
+
return -x
|
25
|
+
end
|
26
|
+
|
27
|
+
def equal(x,y)
|
28
|
+
return (x == y) ? 1 : 0
|
29
|
+
end
|
30
|
+
|
31
|
+
def greater(x,y)
|
32
|
+
return (x > y) ? 1 : 0
|
33
|
+
end
|
34
|
+
|
35
|
+
def less(x,y)
|
36
|
+
return (x < y) ? 1 : 0
|
37
|
+
end
|
38
|
+
|
39
|
+
def greater_than_or_equal(x,y)
|
40
|
+
return (x >= y) ? 1 : 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def less_than_or_equal(x,y)
|
44
|
+
return (x <= y) ? 1 : 0
|
45
|
+
end
|
46
|
+
|
47
|
+
def not_equal(x,y)
|
48
|
+
return (x != y) ? 1 : 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def not(x)
|
52
|
+
if x.is_a?(InkList)
|
53
|
+
return (x.size == 0) ? 1 : 0
|
54
|
+
else
|
55
|
+
return (x == 0) ? 1 : 0
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def and(x,y)
|
60
|
+
if x.is_a?(InkList)
|
61
|
+
return (x.size > 0 && y.size > 0) ? 1 : 0
|
62
|
+
else
|
63
|
+
return (x != 0 && y != 0) ? 1 : 0
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def or(x,y)
|
68
|
+
if x.is_a?(InkList)
|
69
|
+
return (x.size > 0 || y.size > 0) ? 1 : 0
|
70
|
+
else
|
71
|
+
return (x != 0 || y != 0) ? 1 : 0
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def max(x,y)
|
76
|
+
return [x,y].max
|
77
|
+
end
|
78
|
+
|
79
|
+
def min(x,y)
|
80
|
+
return [x,y].min
|
81
|
+
end
|
82
|
+
|
83
|
+
def pow(x,y)
|
84
|
+
return x ** y
|
85
|
+
end
|
86
|
+
|
87
|
+
def floor(x)
|
88
|
+
x.floor.to_f
|
89
|
+
end
|
90
|
+
|
91
|
+
def ceiling(x)
|
92
|
+
x.ceil.to_f
|
93
|
+
end
|
94
|
+
|
95
|
+
def int_value(x)
|
96
|
+
x.to_i
|
97
|
+
end
|
98
|
+
|
99
|
+
def float_value(x)
|
100
|
+
x.to_f
|
101
|
+
end
|
102
|
+
|
103
|
+
def has(x,y)
|
104
|
+
if x.is_a?(InkList)
|
105
|
+
return x.contains?(y) ? 1 : 0
|
106
|
+
else
|
107
|
+
return x.include?(y) ? 1 : 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def has_not(x,y)
|
112
|
+
has_return = has(x,y)
|
113
|
+
# Need to invert values
|
114
|
+
if has_return == 0
|
115
|
+
return 1
|
116
|
+
else
|
117
|
+
return 0
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def intersection(x,y)
|
122
|
+
return x & y
|
123
|
+
end
|
124
|
+
|
125
|
+
def invert(x)
|
126
|
+
x.inverse
|
127
|
+
end
|
128
|
+
|
129
|
+
def all(x)
|
130
|
+
x.all
|
131
|
+
end
|
132
|
+
|
133
|
+
def list_min(x)
|
134
|
+
x.min_as_list
|
135
|
+
end
|
136
|
+
|
137
|
+
def list_max(x)
|
138
|
+
x.max_as_list
|
139
|
+
end
|
140
|
+
|
141
|
+
def count(x)
|
142
|
+
x.count
|
143
|
+
end
|
144
|
+
|
145
|
+
def value_of_list(x)
|
146
|
+
x.max_item[1]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|