algebrick 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/README_FULL.md +13 -21
  4. data/VERSION +1 -1
  5. data/doc/actor.rb +21 -0
  6. data/doc/data.in.rb +99 -0
  7. data/doc/data.out.rb +103 -0
  8. data/doc/extending_behavior.in.rb +61 -0
  9. data/doc/extending_behavior.out.rb +62 -0
  10. data/doc/format.rb +75 -0
  11. data/doc/init.rb +1 -0
  12. data/doc/json.in.rb +39 -0
  13. data/doc/json.out.rb +43 -0
  14. data/doc/null.in.rb +36 -0
  15. data/doc/null.out.rb +40 -0
  16. data/doc/parametrized.in.rb +37 -0
  17. data/doc/parametrized.out.rb +41 -0
  18. data/doc/pattern_matching.in.rb +116 -0
  19. data/doc/pattern_matching.out.rb +122 -0
  20. data/doc/quick_example.in.rb +27 -0
  21. data/doc/quick_example.out.rb +27 -0
  22. data/doc/tree1.in.rb +10 -0
  23. data/doc/tree1.out.rb +10 -0
  24. data/doc/type_def.in.rb +21 -0
  25. data/doc/type_def.out.rb +21 -0
  26. data/doc/values.in.rb +52 -0
  27. data/doc/values.out.rb +58 -0
  28. data/lib/algebrick/atom.rb +49 -0
  29. data/lib/algebrick/dsl.rb +104 -0
  30. data/lib/algebrick/field_method_readers.rb +43 -0
  31. data/lib/algebrick/matcher_delegations.rb +45 -0
  32. data/lib/algebrick/matchers/abstract.rb +127 -0
  33. data/lib/algebrick/matchers/abstract_logic.rb +38 -0
  34. data/lib/algebrick/matchers/and.rb +29 -0
  35. data/lib/algebrick/matchers/any.rb +37 -0
  36. data/lib/algebrick/matchers/array.rb +57 -0
  37. data/lib/algebrick/matchers/atom.rb +28 -0
  38. data/lib/algebrick/matchers/not.rb +44 -0
  39. data/lib/algebrick/matchers/or.rb +51 -0
  40. data/lib/algebrick/matchers/product.rb +73 -0
  41. data/lib/algebrick/matchers/variant.rb +29 -0
  42. data/lib/algebrick/matchers/wrapper.rb +57 -0
  43. data/lib/algebrick/matchers.rb +31 -0
  44. data/lib/algebrick/matching.rb +62 -0
  45. data/lib/algebrick/parametrized_type.rb +122 -0
  46. data/lib/algebrick/product_constructors/abstract.rb +70 -0
  47. data/lib/algebrick/product_constructors/basic.rb +47 -0
  48. data/lib/algebrick/product_constructors/named.rb +58 -0
  49. data/lib/algebrick/product_constructors.rb +25 -0
  50. data/lib/algebrick/product_variant.rb +195 -0
  51. data/lib/algebrick/reclude.rb +39 -0
  52. data/lib/algebrick/serializer.rb +129 -0
  53. data/lib/algebrick/serializers.rb +25 -0
  54. data/lib/algebrick/type.rb +61 -0
  55. data/lib/algebrick/type_check.rb +58 -0
  56. data/lib/algebrick/types.rb +59 -0
  57. data/lib/algebrick/value.rb +41 -0
  58. data/lib/algebrick.rb +14 -1170
  59. data/spec/algebrick_test.rb +708 -0
  60. metadata +105 -27
data/lib/algebrick.rb CHANGED
@@ -21,8 +21,6 @@
21
21
  # TODO gemmify reclude
22
22
  # TODO gemmify typecheck
23
23
 
24
- require 'monitor'
25
-
26
24
 
27
25
  # Provides Algebraic types and pattern matching
28
26
  #
@@ -34,1173 +32,19 @@ module Algebrick
34
32
  @version ||= Gem::Version.new File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
35
33
  end
36
34
 
37
- # fix module to re-include itself to where it was already included when a module is included into it
38
- module Reclude
39
- def included(base)
40
- included_into << base
41
- super base
42
- end
43
-
44
- def include(*modules)
45
- super(*modules)
46
- modules.reverse.each do |module_being_included|
47
- included_into.each do |mod|
48
- mod.send :include, module_being_included
49
- end
50
- end
51
- end
52
-
53
- private
54
-
55
- def included_into
56
- @included_into ||= []
57
- end
58
- end
59
-
60
- module TypeCheck
61
- # FIND: type checking of collections?
62
-
63
- def Type?(value, *types)
64
- types.any? { |t| value.is_a? t }
65
- end
66
-
67
- def Type!(value, *types)
68
- Type?(value, *types) or
69
- TypeCheck.error(value, 'is not', types)
70
- value
71
- end
72
-
73
- def Match?(value, *types)
74
- types.any? { |t| t === value }
75
- end
76
-
77
- def Match!(value, *types)
78
- Match?(value, *types) or
79
- TypeCheck.error(value, 'is not matching', types)
80
- value
81
- end
82
-
83
- def Child?(value, *types)
84
- Type?(value, Class) &&
85
- types.any? { |t| value <= t }
86
- end
87
-
88
- def Child!(value, *types)
89
- Child?(value, *types) or
90
- TypeCheck.error(value, 'is not child', types)
91
- value
92
- end
93
-
94
- private
95
-
96
- def self.error(value, message, types)
97
- raise TypeError,
98
- "Value (#{value.class}) '#{value}' #{message} any of: #{types.join('; ')}."
99
- end
100
- end
101
-
102
- # include this module anywhere yoy need to use pattern matching
103
- module Matching
104
- def any
105
- Matchers::Any.new
106
- end
107
-
108
- def match(value, *cases)
109
- cases = if cases.size == 1 && cases.first.is_a?(Hash)
110
- cases.first
111
- else
112
- cases
113
- end
114
-
115
- cases.each do |matcher, block|
116
- return Matching.match_value matcher, block if matcher === value
117
- end
118
- raise "no match for (#{value.class}) '#{value}' by any of #{cases.map(&:first).join ', '}"
119
- end
120
-
121
- def on(matcher, value = nil, &block)
122
- matcher = if matcher.is_a? Matchers::Abstract
123
- matcher
124
- else
125
- matcher.to_m
126
- end
127
- raise ArgumentError, 'only one of block or value can be supplied' if block && value
128
- [matcher, value || block]
129
- end
130
-
131
- # FIND: #match! raise when match is not complete on a given type
132
-
133
- private
134
-
135
- def self.match_value(matcher, block)
136
- if block.kind_of? Proc
137
- if matcher.kind_of? Matchers::Abstract
138
- matcher.assigns &block
139
- else
140
- block.call
141
- end
142
- else
143
- block
144
- end
145
- end
146
- end
147
-
148
- include Matching
149
- extend Matching
150
-
151
- module MatcherDelegations
152
- def ~
153
- ~to_m
154
- end
155
-
156
- def &(other)
157
- to_m & other
158
- end
159
-
160
- def |(other)
161
- to_m | other
162
- end
163
-
164
- def !
165
- !to_m
166
- end
167
-
168
- def case(&block)
169
- to_m.case &block
170
- end
171
-
172
- def >>(block)
173
- to_m >> block
174
- end
175
-
176
- def >(block)
177
- to_m > block
178
- end
179
- end
180
-
181
- # Any Algebraic type defined by Algebrick is kind of Type
182
- class Type < Module
183
- include TypeCheck
184
- include Matching
185
- include MatcherDelegations
186
- include Reclude
187
-
188
- def initialize(name, &definition)
189
- super &definition
190
- @name = name
191
- end
192
-
193
- def name
194
- super || @name
195
- end
196
-
197
- def to_m(*args)
198
- raise NotImplementedError
199
- end
200
-
201
- def ==(other)
202
- raise NotImplementedError
203
- end
204
-
205
- def be_kind_of(type)
206
- raise NotImplementedError
207
- end
208
-
209
- def to_s
210
- raise NotImplementedError
211
- end
212
-
213
- def inspect
214
- to_s
215
- end
216
- end
217
-
218
- # Any value of Algebraic type is kind of Value
219
- module Value
220
- include TypeCheck
221
- include Matching
222
-
223
- def ==(other)
224
- raise NotImplementedError
225
- end
226
-
227
- def type
228
- raise NotImplementedError
229
- end
230
-
231
- def to_hash
232
- raise NotImplementedError
233
- end
234
-
235
- def to_s
236
- raise NotImplementedError
237
- end
238
-
239
- def inspect
240
- to_s
241
- end
242
- end
243
-
244
- TYPE_KEY = :algebrick
245
- FIELDS_KEY = :fields
246
-
247
- # Representation of Atomic types
248
- class Atom < Type
249
- include Value
250
-
251
- def initialize(name, &block)
252
- super name, &block
253
- extend self
254
- end
255
-
256
- def to_m
257
- Matchers::Atom.new self
258
- end
259
-
260
- def be_kind_of(type)
261
- extend type
262
- end
263
-
264
- def ==(other)
265
- self.equal? other
266
- end
267
-
268
- def type
269
- self
270
- end
271
-
272
- def to_s
273
- name
274
- end
275
-
276
- def to_hash
277
- { TYPE_KEY => name }
278
- end
279
-
280
- def from_hash(hash)
281
- if hash == to_hash
282
- self
283
- else
284
- raise ArgumentError
285
- end
286
- end
287
- end
288
-
289
- # A private class used for Product values creation
290
- class ProductConstructor
291
- include Value
292
- attr_reader :fields
293
-
294
- def initialize(*fields)
295
- if fields.size == 1 && fields.first.is_a?(Hash)
296
- fields = type.field_names.map { |k| fields.first[k] }
297
- end
298
- @fields = fields.zip(self.class.type.fields).map { |field, type| Type! field, type }.freeze
299
- end
300
-
301
- def to_s
302
- "#{self.class.type.name}[" +
303
- if type.field_names?
304
- type.field_names.map { |name| "#{name}: #{self[name].to_s}" }.join(', ')
305
- else
306
- fields.map(&:to_s).join(', ')
307
- end + ']'
308
- end
309
-
310
- def pretty_print(q)
311
- q.group(1, "#{self.class.type.name}[", ']') do
312
- if type.field_names?
313
- type.field_names.each_with_index do |name, i|
314
- if i == 0
315
- q.breakable ''
316
- else
317
- q.text ','
318
- q.breakable ' '
319
- end
320
- q.text name.to_s
321
- q.text ':'
322
- q.group(1) do
323
- q.breakable ' '
324
- q.pp self[name]
325
- end
326
- end
327
- else
328
- fields.each_with_index do |value, i|
329
- if i == 0
330
- q.breakable ''
331
- else
332
- q.text ','
333
- q.breakable ' '
334
- end
335
- q.pp value
336
- end
337
- end
338
- end
339
- end
340
-
341
- def to_ary
342
- @fields
343
- end
344
-
345
- def to_a
346
- @fields
347
- end
348
-
349
- def to_hash
350
- { TYPE_KEY => self.class.type.name }.
351
- update(if type.field_names?
352
- type.field_names.inject({}) { |h, name| h.update name => hashize(self[name]) }
353
- else
354
- { FIELDS_KEY => fields.map { |v| hashize v } }
355
- end)
356
- end
357
-
358
- def ==(other)
359
- return false unless other.kind_of? self.class
360
- @fields == other.fields
361
- end
362
-
363
- def self.type
364
- @type || raise
365
- end
366
-
367
- def type
368
- self.class.type
369
- end
370
-
371
- def self.name
372
- @type.to_s
373
- end
374
-
375
- def self.to_s
376
- name
377
- end
378
-
379
- def self.type=(type)
380
- raise if @type
381
- @type = type
382
- include type
383
- end
384
-
385
- private
386
-
387
- def hashize(value)
388
- (value.respond_to? :to_hash) ? value.to_hash : value
389
- end
390
- end
391
-
392
- # Representation of Product and Variant types. The class behaves differently
393
- # based on #kind.
394
- class ProductVariant < Type
395
- attr_reader :fields, :variants
396
-
397
- def initialize(name, &definition)
398
- super(name, &definition)
399
- @to_be_kind_of = []
400
- end
401
-
402
- def set_fields(fields_or_hash)
403
- raise TypeError, 'can be set only once' if @fields
404
- fields, keys = case fields_or_hash
405
- when Hash
406
- [fields_or_hash.values, fields_or_hash.keys]
407
- when Array
408
- [fields_or_hash, nil]
409
- else
410
- raise ArgumentError
411
- end
412
-
413
- add_field_names keys if keys
414
-
415
- fields.all? { |f| Type! f, Type, Class, Module }
416
- raise TypeError, 'there is no product with zero fields' unless fields.size > 0
417
- define_method(:value) { @fields.first } if fields.size == 1
418
- @fields = fields
419
- @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
420
- apply_be_kind_of
421
- self
422
- end
423
-
424
- def field_names
425
- @field_names or raise TypeError, "field names not defined on #{self}"
426
- end
427
-
428
- def field_names?
429
- !!@field_names
430
- end
431
-
432
- def field_indexes
433
- @field_indexes or raise TypeError, "field names not defined on #{self}"
434
- end
435
-
436
- def add_field_method_reader(field)
437
- raise TypeError, 'no field names' unless field_names?
438
- raise ArgumentError, "no field name #{field}" unless field_names.include? field
439
- raise ArgumentError, "method #{field} already defined" if instance_methods.include? field
440
- define_method(field) { self[field] }
441
- self
442
- end
443
-
444
- def add_field_method_readers(*fields)
445
- fields.each { |f| add_field_method_reader f }
446
- self
447
- end
448
-
449
- def add_all_field_method_readers
450
- add_field_method_readers *@field_names
451
- end
452
-
453
- def set_variants(variants)
454
- raise TypeError, 'can be set only once' if @variants
455
- variants.all? { |v| Type! v, Type, Class }
456
- @variants = variants
457
- apply_be_kind_of
458
- variants.each do |v|
459
- if v.respond_to? :be_kind_of
460
- v.be_kind_of self
461
- else
462
- v.send :include, self
463
- end
464
- end
465
- self
466
- end
467
-
468
- def new(*fields)
469
- raise TypeError, "#{self} does not have fields" unless @constructor
470
- @constructor.new *fields
471
- end
472
-
473
- alias_method :[], :new
474
-
475
- def ==(other)
476
- other.kind_of? ProductVariant and
477
- variants == other.variants and fields == other.fields
478
- end
479
-
480
- def be_kind_of(type)
481
- @to_be_kind_of << type
482
- apply_be_kind_of
483
- end
484
-
485
- def apply_be_kind_of
486
- @to_be_kind_of.each do |type|
487
- @constructor.send :include, type if @constructor
488
- variants.each { |v| v.be_kind_of type unless v == self } if @variants
489
- end
490
- end
491
-
492
- def call(*field_matchers)
493
- raise TypeError, "#{self} does not have any fields" unless @fields
494
- Matchers::Product.new self, *field_matchers
495
- end
496
-
497
- def to_m
498
- case kind
499
- when :product
500
- Matchers::Product.new self
501
- when :product_variant
502
- Matchers::Variant.new self
503
- when :variant
504
- Matchers::Variant.new self
505
- else
506
- raise
507
- end
508
- end
509
-
510
- def to_s
511
- case kind
512
- when :product
513
- product_to_s
514
- when :product_variant
515
- name + '(' +
516
- variants.map do |variant|
517
- if variant == self
518
- product_to_s
519
- else
520
- variant.name
521
- end
522
- end.join(' | ') +
523
- ')'
524
- when :variant
525
- "#{name}(#{variants.map(&:name).join ' | '})"
526
- else
527
- raise
528
- end
529
- end
530
-
531
- def from_hash(hash)
532
- case kind
533
- when :product
534
- product_from_hash hash
535
- when :product_variant
536
- product_from_hash hash
537
- when :variant
538
- field_from_hash hash
539
- else
540
- raise
541
- end
542
- end
543
-
544
- def kind
545
- case
546
- when @fields && !@variants
547
- :product
548
- when @fields && @variants
549
- :product_variant
550
- when !@fields && @variants
551
- :variant
552
- when !@fields && !@variants
553
- raise TypeError, 'fields or variants have to be set'
554
- end
555
- end
556
-
557
- def assigned_types
558
- @assigned_types or raise TypeError, "#{self} does not have assigned types"
559
- end
560
-
561
- def assigned_types=(assigned_types)
562
- raise TypeError, "#{self} assigned types already set" if @assigned_types
563
- @assigned_types = assigned_types
564
- end
565
-
566
- private
567
-
568
- def product_to_s
569
- fields_str = if field_names?
570
- field_names.zip(fields).map { |name, field| "#{name}: #{field.name}" }
571
- else
572
- fields.map(&:name)
573
- end
574
- "#{name}(#{fields_str.join ', '})"
575
- end
576
-
577
- def add_field_names(names)
578
- @field_names = names
579
- names.all? { |k| Type! k, Symbol }
580
- dict = @field_indexes =
581
- Hash.new { |h, k| raise ArgumentError, "unknown field #{k.inspect} in #{self}" }.
582
- update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
583
- define_method(:[]) { |key| @fields[dict[key]] }
584
- end
585
-
586
- def product_from_hash(hash)
587
- (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or
588
- raise ArgumentError, "hash does not have #{TYPE_KEY}"
589
- raise ArgumentError, "#{type_name} is not #{name}" unless type_name == name
590
-
591
- fields = hash[FIELDS_KEY] || hash[FIELDS_KEY.to_s] ||
592
- hash.reject { |k, _| k.to_s == TYPE_KEY.to_s }
593
- Type! fields, Hash, Array
594
-
595
- case fields
596
- when Array
597
- self[*fields.map { |value| field_from_hash value }]
598
- when Hash
599
- self[fields.inject({}) do |h, (name, value)|
600
- raise ArgumentError unless field_names.map(&:to_s).include? name.to_s
601
- h.update name.to_sym => field_from_hash(value)
602
- end]
603
- end
604
- end
605
-
606
- def field_from_hash(hash)
607
- return hash unless Hash === hash
608
- (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or return hash
609
- type = constantize type_name
610
- type.from_hash hash
611
- end
612
-
613
- def constantize(camel_cased_word)
614
- names = camel_cased_word.split('::')
615
- names.shift if names.empty? || names.first.empty?
616
-
617
- constant = Object
618
- names.each do |name|
619
- constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
620
- end
621
- constant
622
- end
623
- end
624
-
625
- class ParametrizedType < Module
626
- include TypeCheck
627
- include MatcherDelegations
628
-
629
- attr_reader :variables, :fields, :variants
630
-
631
- def initialize(variables)
632
- @variables = variables.each { |v| Type! v, Symbol }
633
- @fields = nil
634
- @variants = nil
635
- @cache = {}
636
- @cache_barrier = Monitor.new
637
- end
638
-
639
- def set_fields(fields)
640
- @fields = Type! fields, Hash, Array
641
- end
642
-
643
- def field_names
644
- case @fields
645
- when Hash
646
- @fields.keys
647
- when Array, nil
648
- raise TypeError, "field names not defined on #{self}"
649
- else
650
- raise
651
- end
652
- end
653
-
654
- def set_variants(variants)
655
- @variants = Type! variants, Array
656
- end
657
-
658
- def [](*assigned_types)
659
- @cache_barrier.synchronize do
660
- @cache[assigned_types] || begin
661
- raise ArgumentError unless assigned_types.size == variables.size
662
- ProductVariant.new(type_name(assigned_types)).tap do |type|
663
- type.be_kind_of self
664
- @cache[assigned_types] = type
665
- type.assigned_types = assigned_types
666
- type.set_variants insert_types(variants, assigned_types) if variants
667
- type.set_fields insert_types(fields, assigned_types) if fields
668
- end
669
- end
670
- end
671
- end
672
-
673
- def to_s
674
- "#{name}[#{variables.join(', ')}]"
675
- end
676
-
677
- def inspect
678
- to_s
679
- end
680
-
681
- def to_m
682
- if @variants
683
- Matchers::Variant.new self
684
- else
685
- Matchers::Product.new self
686
- end
687
- end
688
-
689
- def call(*field_matchers)
690
- raise TypeError unless @fields
691
- Matchers::Product.new self, *field_matchers
692
- end
693
-
694
- private
695
-
696
- def insert_types(types, assigned_types)
697
- case types
698
- when Hash
699
- types.inject({}) { |h, (k, v)| h.update k => insert_type(v, assigned_types) }
700
- when Array
701
- types.map { |v| insert_type v, assigned_types }
702
- else
703
- raise ArgumentError
704
- end
705
- end
706
-
707
- def insert_type(type, assigned_types)
708
- case type
709
- when Symbol
710
- assigned_types[variables.index type]
711
- when ParametrizedType
712
- type[*type.variables.map { |v| assigned_types[variables.index v] }]
713
- else
714
- type
715
- end
716
- end
717
-
718
- def type_name(assigned_types)
719
- "#{name}[#{assigned_types.join(', ')}]"
720
- end
721
- end
722
-
723
- module DSL
724
- module Shortcuts
725
- def type(*variables, &block)
726
- Algebrick.type *variables, &block
727
- end
728
-
729
- def atom
730
- Algebrick.atom
731
- end
732
- end
733
-
734
- class TypeDefinitionScope
735
- include Shortcuts
736
- include TypeCheck
737
-
738
- attr_reader :new_type
739
-
740
- def initialize(new_type, &block)
741
- @new_type = Type! new_type, ProductVariant, ParametrizedType
742
- instance_exec @new_type, &block
743
- @new_type.kind if @new_type.is_a? ProductVariant
744
- end
745
-
746
- def fields(*fields)
747
- @new_type.set_fields fields.first.is_a?(Hash) ? fields.first : fields
748
- self
749
- end
750
-
751
- def fields!(*fields)
752
- fields(*fields)
753
- all_readers
754
- end
755
-
756
- def variants(*variants)
757
- @new_type.set_variants variants
758
- self
759
- end
760
-
761
- def field_readers(*names)
762
- @new_type.add_field_method_readers *names
763
- self
764
- end
765
-
766
- alias_method :readers, :field_readers
767
-
768
- def all_field_readers
769
- @new_type.add_all_field_method_readers
770
- self
771
- end
772
-
773
- alias_method :all_readers, :all_field_readers
774
- end
775
-
776
- class OuterShell
777
- include Shortcuts
778
-
779
- def initialize(&block)
780
- instance_eval &block
781
- end
782
- end
783
- end
784
-
785
- def self.type(*variables, &block)
786
- if block.nil?
787
- raise 'Atom canot be parametrized' unless variables.empty?
788
- atom
789
- else
790
- if variables.empty?
791
- DSL::TypeDefinitionScope.new(ProductVariant.new(nil), &block).new_type
792
- else
793
- DSL::TypeDefinitionScope.new(ParametrizedType.new(variables), &block).new_type
794
- end
795
- end
796
- end
797
-
798
- def self.atom
799
- Atom.new nil
800
- end
801
-
802
- def self.types(&block)
803
- DSL::OuterShell.new &block
804
- end
805
-
806
- module Matchers
807
-
808
- class Abstract
809
- include TypeCheck
810
- attr_reader :value
811
-
812
- def initialize
813
- @assign, @value, @matched = nil
814
- end
815
-
816
- def case(&block)
817
- return self, block
818
- end
819
-
820
- alias_method :when, :case
821
-
822
- def >(block)
823
- return self, block
824
- end
825
-
826
- alias_method :>>, :>
827
-
828
- def ~
829
- @assign = true
830
- self
831
- end
832
-
833
- def &(matcher)
834
- And.new self, matcher
835
- end
836
-
837
- def |(matcher)
838
- Or.new self, matcher
839
- end
840
-
841
- def !
842
- Not.new self
843
- end
844
-
845
- def assign?
846
- @assign
847
- end
848
-
849
- def matched?
850
- @matched
851
- end
852
-
853
- def children_including_self
854
- children.unshift self
855
- end
856
-
857
- def assigns
858
- collect_assigns.tap do
859
- return yield *assigns if block_given?
860
- end
861
- end
862
-
863
- def to_a
864
- assigns
865
- end
866
-
867
- def ===(other)
868
- matching?(other).tap { |matched| @value = other if (@matched = matched) }
869
- end
870
-
871
- def assign_to_s
872
- assign? ? '~' : ''
873
- end
874
-
875
- def inspect
876
- to_s
877
- end
878
-
879
- def children
880
- raise NotImplementedError
881
- end
882
-
883
- def to_s
884
- raise NotImplementedError
885
- end
886
-
887
- def ==(other)
888
- raise NotImplementedError
889
- end
890
-
891
- protected
892
-
893
- def matching?(other)
894
- raise NotImplementedError
895
- end
896
-
897
- private
898
-
899
- def collect_assigns
900
- mine = @assign ? [@value] : []
901
- children.inject(mine) { |assigns, child| assigns + child.assigns }
902
- end
903
-
904
- def matchable!(obj)
905
- raise ArgumentError, 'object does not respond to :===' unless obj.respond_to? :===
906
- obj
907
- end
908
-
909
- def find_children(collection)
910
- collection.map do |matcher|
911
- matcher if matcher.kind_of? Abstract
912
- end.compact
913
- end
914
- end
915
-
916
- class AbstractLogic < Abstract
917
- def self.call(*matchers)
918
- new *matchers
919
- end
920
-
921
- attr_reader :matchers
922
-
923
- def initialize(*matchers)
924
- @matchers = matchers.each { |m| matchable! m }
925
- end
926
-
927
- def children
928
- find_children matchers
929
- end
930
-
931
- def ==(other)
932
- other.kind_of? self.class and
933
- self.matchers == other.matchers
934
- end
935
- end
936
-
937
- class And < AbstractLogic
938
- def to_s
939
- matchers.join ' & '
940
- end
941
-
942
- protected
943
-
944
- def matching?(other)
945
- matchers.all? { |m| m === other }
946
- end
947
- end
948
-
949
- class Or < AbstractLogic
950
- def to_s
951
- matchers.join ' | '
952
- end
953
-
954
- protected
955
-
956
- def matching?(other)
957
- matchers.any? { |m| m === other }
958
- end
959
-
960
- alias_method :super_children, :children
961
- private :super_children
962
-
963
- def children
964
- super.select &:matched?
965
- end
966
-
967
- private
968
-
969
- def collect_assigns
970
- super.tap do |assigns|
971
- missing = assigns_size - assigns.size
972
- assigns.push(*::Array.new(missing))
973
- end
974
- end
975
-
976
- def assigns_size
977
- # TODO is it efficient?
978
- super_children.map { |ch| ch.assigns.size }.max
979
- end
980
- end
981
-
982
- class Not < Abstract
983
- attr_reader :matcher
984
-
985
- def initialize(matcher)
986
- @matcher = matcher
987
- end
988
-
989
- def children
990
- []
991
- end
992
-
993
- def to_s
994
- '!' + matcher.to_s
995
- end
996
-
997
- def ==(other)
998
- other.kind_of? self.class and
999
- self.matcher == other.matcher
1000
- end
1001
-
1002
- protected
1003
-
1004
- def matching?(other)
1005
- not matcher === other
1006
- end
1007
- end
1008
-
1009
- class Any < Abstract
1010
- def children
1011
- []
1012
- end
1013
-
1014
- def to_s
1015
- assign_to_s + 'any'
1016
- end
1017
-
1018
- def ==(other)
1019
- other.kind_of? self.class
1020
- end
1021
-
1022
- protected
1023
-
1024
- def matching?(other)
1025
- true
1026
- end
1027
- end
1028
-
1029
- class Wrapper < Abstract
1030
- def self.call(something)
1031
- new something
1032
- end
1033
-
1034
- attr_reader :something
1035
-
1036
- def initialize(something)
1037
- super()
1038
- @something = matchable! something
1039
- end
1040
-
1041
- def children
1042
- find_children [@something]
1043
- end
1044
-
1045
- def to_s
1046
- assign_to_s + "Wrapper.(#{@something})"
1047
- end
1048
-
1049
- def ==(other)
1050
- other.kind_of? self.class and
1051
- self.something == other.something
1052
- end
1053
-
1054
- protected
1055
-
1056
- def matching?(other)
1057
- @something === other
1058
- end
1059
- end
1060
-
1061
- class ::Object
1062
- def to_m
1063
- Wrapper.new(self)
1064
- end
1065
- end
1066
-
1067
- class Array < Abstract
1068
- def self.call(*matchers)
1069
- new *matchers
1070
- end
1071
-
1072
- attr_reader :matchers
1073
-
1074
- def initialize(*matchers)
1075
- super()
1076
- @matchers = matchers
1077
- end
1078
-
1079
- def children
1080
- find_children @matchers
1081
- end
1082
-
1083
- def to_s
1084
- "#{assign_to_s}#{"Array.(#{matchers.join(',')})" if matchers}"
1085
- end
1086
-
1087
- def ==(other)
1088
- other.kind_of? self.class and
1089
- self.matchers == other.matchers
1090
- end
1091
-
1092
- protected
1093
-
1094
- def matching?(other)
1095
- other.kind_of? ::Array and
1096
- matchers.size == other.size and
1097
- matchers.each_with_index.all? { |m, i| m === other[i] }
1098
- end
1099
- end
1100
-
1101
- class ::Array
1102
- def self.call(*matchers)
1103
- Matchers::Array.new *matchers
1104
- end
1105
- end
1106
-
1107
- class Product < Abstract
1108
- attr_reader :algebraic_type, :field_matchers
1109
-
1110
- def initialize(algebraic_type, *field_matchers)
1111
- super()
1112
- @algebraic_type = Type! algebraic_type, Algebrick::ProductVariant, Algebrick::ParametrizedType
1113
- raise ArgumentError unless algebraic_type.fields
1114
- @field_matchers = case
1115
-
1116
- # AProduct.()
1117
- when field_matchers.empty?
1118
- ::Array.new(algebraic_type.fields.size) { Algebrick.any }
1119
-
1120
- # AProduct.(field_name: a_matcher)
1121
- when field_matchers.size == 1 && field_matchers.first.is_a?(Hash)
1122
- field_matchers = field_matchers.first
1123
- unless (dif = field_matchers.keys - algebraic_type.field_names).empty?
1124
- raise ArgumentError, "no #{dif} fields in #{algebraic_type}"
1125
- end
1126
- algebraic_type.field_names.map do |field|
1127
- field_matchers.key?(field) ? field_matchers[field] : Algebrick.any
1128
- end
1129
-
1130
- # normal
1131
- else
1132
- field_matchers
1133
- end
1134
- unless algebraic_type.fields.size == @field_matchers.size
1135
- raise ArgumentError
1136
- end
1137
- end
1138
-
1139
- def children
1140
- find_children @field_matchers
1141
- end
1142
-
1143
- def to_s
1144
- assign_to_s + "#{@algebraic_type.name}.(#{@field_matchers.join(', ')})"
1145
- end
1146
-
1147
- # TODO prety_print for all matchers
1148
-
1149
- def ==(other)
1150
- other.kind_of? self.class and
1151
- self.algebraic_type == other.algebraic_type and
1152
- self.field_matchers == other.field_matchers
1153
- end
1154
-
1155
- protected
1156
-
1157
- def matching?(other)
1158
- other.kind_of?(@algebraic_type) and other.kind_of?(ProductConstructor) and
1159
- @field_matchers.zip(other.fields).all? do |matcher, field|
1160
- matcher === field
1161
- end
1162
- end
1163
- end
1164
-
1165
- class Variant < Wrapper
1166
- def initialize(something)
1167
- raise ArgumentError unless something.variants
1168
- Type! something, Algebrick::ProductVariant
1169
- super something
1170
- end
1171
-
1172
- def to_s
1173
- assign_to_s + "#{@something.name}.to_m"
1174
- end
1175
- end
1176
-
1177
- class Atom < Wrapper
1178
- def initialize(something)
1179
- Type! something, Algebrick::Atom
1180
- super something
1181
- end
1182
-
1183
- def to_s
1184
- assign_to_s + "#{@something.name}.to_m"
1185
- end
1186
- end
1187
- end
1188
-
1189
- module Types
1190
- Maybe = Algebrick.type(:v) do
1191
- variants None = atom,
1192
- Some = type(:v) { fields :v }
1193
- end
1194
-
1195
- module Maybe
1196
- def maybe
1197
- match self,
1198
- None >> nil,
1199
- Some >-> { yield value }
1200
- end
1201
- end
1202
- end
1203
-
1204
- include Types
35
+ require 'algebrick/reclude'
36
+ require 'algebrick/type_check'
37
+ require 'algebrick/matching'
38
+ require 'algebrick/matcher_delegations'
39
+ require 'algebrick/type'
40
+ require 'algebrick/value'
41
+ require 'algebrick/atom'
42
+ require 'algebrick/product_constructors'
43
+ require 'algebrick/field_method_readers'
44
+ require 'algebrick/product_variant'
45
+ require 'algebrick/parametrized_type'
46
+ require 'algebrick/dsl'
47
+ require 'algebrick/matchers'
48
+ require 'algebrick/types'
1205
49
 
1206
50
  end