algebrick 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -7
  3. data/README_FULL.md +10 -11
  4. data/VERSION +1 -1
  5. data/lib/algebrick.rb +770 -348
  6. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fb30a6eeabbe7769c1f946395bef047d5acf4362
4
- data.tar.gz: 5c0289625f919dffe3f57e6fa2e258ca353d4ba9
3
+ metadata.gz: 7f70cafbfe1296efd6042757bf59917fb2f290aa
4
+ data.tar.gz: 3466daa431dd466059085c9e6acf42eb872a7335
5
5
  SHA512:
6
- metadata.gz: 0932e96464a044f3e2a9138efcd07433bf17fb747f1718b73354599750b84543e70f7b29a97db0854343f6f25c04eda02bc6baa8498a90e5feb55f2ac57437ad
7
- data.tar.gz: 7bf6898feafadd9694cf898b61c81c9879fcc0dc628044244eed4f9ec5c8d1b3d2888b826305a73d463e08621f79e6759a75b5c84283a4bb48c617d27469671f
6
+ metadata.gz: 37ea095790d58c8995686a70e4a25936db720d40f28b35ebdefab1e25da4395124cca6aed2f93fd5ee7f0d6d82532d55e05d428121e824b8ffcdb9829ac3b0a7
7
+ data.tar.gz: 779756c205b84c25f756ad8f2d8658806d9023db3c015f848ffcfb69d6b157686287fa5d3aa06c95745924d70192c87e10d78ed5ddd2cb22e5047d332d9047a1
data/README.md CHANGED
@@ -11,24 +11,25 @@ It's a small gem providing **algebraic types** and **pattern matching** on them
11
11
  ## What is it good for?
12
12
 
13
13
  - Defining data structures.
14
- - Algebraic types play nice with JSON serialization and deserialization. It is ideal for defining
15
- message-based cross-process communication.
14
+ - Algebraic types play nice with JSON serialization and deserialization. It is ideal for defining message-based cross-process communication.
16
15
  - and more...
17
16
 
18
17
  ## Quick example
19
18
 
20
- Load DSL for type definition and define some algebraic types
19
+ Let's define a Tree
21
20
 
22
21
  ```ruby
23
- extend Algebrick::DSL
22
+ Tree = Algebrick.type do |tree|
23
+ Empty = type
24
+ Leaf = type { fields Integer }
25
+ Node = type { fields tree, tree }
24
26
 
25
- type_def do
26
- tree === empty | leaf(Integer) | node(tree, tree)
27
+ variants Empty, Leaf, Node
27
28
  end
28
29
  ```
29
30
 
30
31
  Now types `Tree(Empty | Leaf | Node)`, `Empty`, `Leaf(Integer)` and `Node(Tree, Tree)` are defined.
31
- Lets add some methods, don't miss the **pattern matching** example.
32
+ Add some methods, don't miss the **pattern matching** example.
32
33
 
33
34
  ```ruby
34
35
  module Tree
data/README_FULL.md CHANGED
@@ -26,14 +26,14 @@ Same thing can be defined with this gem:
26
26
 
27
27
  {include:file:doc/tree1.out.rb}
28
28
 
29
- There are 4 kinds of algebraic types in Algebrick gem:
29
+ There are 4 kinds of algebraic types:
30
30
 
31
- - **Atom** a type that has only one value e.g. `Empty`.
32
- - **Product** a type that has a set nuber of fields with given type e.g. `Leaf(Integer)`
33
- - **Variant** a type that does have set number of variants e.g. `Tree(Empty | Leaf(Integer) | Node(Tree, Tree)`.
34
- It means that values of `Empty`, `Leaf[1]`, `Node[Empty, Empry]` have all type `Tree`.
35
- - **ProductVariant** will be created when a recursive type like `list === empty | list(Object, list)` is defined.
36
- `List` has two variants `Empty` and itself simultaneously it has fields as product type.
31
+ 1. **Atom** a type that has only one value e.g. `Empty`.
32
+ 2. **Product** a type that has a set number of fields with given type e.g. `Leaf(Integer)`
33
+ 3. **Variant** a type that does have set number of variants e.g. `Tree(Empty | Leaf(Integer) | Node(Tree, Tree)`. It means that values of `Empty`, `Leaf[1]`, `Node[Empty, Empry]` are all of type `Tree`.
34
+ 4. **ProductVariant** will be created when a recursive type like `List(Empty | List(Integer, List))` is defined. `List` has two variants `Empty` and itself, and simultaneously it has fields as product type.
35
+
36
+ Atom type is implemented with {Algebrick::Atom} and the rest is implemented with {Algebrick::ProductVariant} which behaves differently based on what is set: fields, variants or both.
37
37
 
38
38
  ### Type definition
39
39
 
@@ -49,7 +49,7 @@ There are 4 kinds of algebraic types in Algebrick gem:
49
49
 
50
50
  ### Pattern matching
51
51
 
52
- Algebraic matchers are helper objects to match algebraic objects and others with
52
+ Algebraic matchers are helper objects to match algebraic values and others with
53
53
  `#===` method based on theirs initialization values.
54
54
 
55
55
  {include:file:doc/pattern_matching.out.rb}
@@ -88,7 +88,7 @@ Just small snippet from a gem I am still working on.
88
88
 
89
89
  def on_message(message)
90
90
  match message,
91
- Work.(~any, ~any) --> actor, work do
91
+ Work.(~any, ~any) >-> actor, work do
92
92
  @executor.tell Finished[actor, work.call, self.reference]
93
93
  end
94
94
  end
@@ -97,6 +97,5 @@ Just small snippet from a gem I am still working on.
97
97
  ### TODO
98
98
 
99
99
  - Menu model, TypedArray
100
- - Pretty print example, see {http://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf}
101
100
  - update actor pattern when gem is done
102
-
101
+ - example with birth-number Valid|Invalid
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.2.0
data/lib/algebrick.rb CHANGED
@@ -18,14 +18,14 @@
18
18
 
19
19
  require 'set'
20
20
 
21
- class Module
22
- # Return any modules we +extend+
23
- def extended_modules
24
- class << self
25
- self
26
- end.included_modules
27
- end
28
- end
21
+ #class Module
22
+ # # Return any modules we +extend+
23
+ # def extended_modules
24
+ # class << self
25
+ # self
26
+ # end.included_modules
27
+ # end
28
+ #end
29
29
 
30
30
  module Algebrick
31
31
 
@@ -78,8 +78,8 @@ module Algebrick
78
78
  alias_method :_, :any # TODO make it optional
79
79
 
80
80
  #match Empty,
81
- # Empty -->() {},
82
- # Leaf.(~any) >>-> value do
81
+ # Empty >> static_value_like_string,
82
+ # Leaf.(~any) >-> value do
83
83
  # value
84
84
  # end
85
85
  #match Empty,
@@ -139,6 +139,10 @@ module Algebrick
139
139
  to_m | other
140
140
  end
141
141
 
142
+ def ^(other)
143
+ to_m ^ other
144
+ end
145
+
142
146
  def !
143
147
  !to_m
144
148
  end
@@ -154,6 +158,10 @@ module Algebrick
154
158
  def >>(block)
155
159
  to_m >> block
156
160
  end
161
+
162
+ def >(block)
163
+ to_m > block
164
+ end
157
165
  end
158
166
 
159
167
  class Type < Module
@@ -161,6 +169,15 @@ module Algebrick
161
169
  include Matching
162
170
  include MatcherDelegations
163
171
 
172
+ def initialize(name, &definition)
173
+ super &definition
174
+ @name = name
175
+ end
176
+
177
+ def name
178
+ super || @name
179
+ end
180
+
164
181
  def to_m(*args)
165
182
  raise NotImplementedError
166
183
  end
@@ -213,8 +230,8 @@ module Algebrick
213
230
  class Atom < Type
214
231
  include Value
215
232
 
216
- def initialize(&block)
217
- super &block
233
+ def initialize(name, &block)
234
+ super name, &block
218
235
  extend self
219
236
  end
220
237
 
@@ -316,55 +333,11 @@ module Algebrick
316
333
  end
317
334
  end
318
335
 
319
- class AbstractProductVariant < Type
320
- def be_kind_of(type = nil)
321
- if initialized?
322
- be_kind_of! type if type
323
- if @to_be_kind_of
324
- while (type = @to_be_kind_of.shift)
325
- be_kind_of! type
326
- end
327
- end
328
- else
329
- @to_be_kind_of ||= []
330
- @to_be_kind_of << type if type
331
- end
332
- self
333
- end
334
-
335
- def add_field_method_accessor(field)
336
- raise TypeError, 'no field names' unless @field_names
337
- raise TypeError, "no field name #{field}" unless @field_names.include? field
338
- define_method(field) { self[field] }
339
- end
340
-
341
- def add_field_method_accessors(*fields)
342
- fields.each { |f| add_field_method_accessor f }
343
- end
344
-
345
- def add_all_field_method_accessors
346
- add_field_method_accessors *@field_names
347
- end
348
-
349
- protected
350
-
351
- def be_kind_of!(type)
352
- raise NotImplementedError
353
- end
354
-
355
- private
356
-
357
- def initialized?
358
- !!@initialized
359
- end
360
-
361
- def initialize(&block)
362
- super &block
363
- @initialized = true
364
- be_kind_of
365
- end
336
+ class ProductVariant < Type
337
+ attr_reader :fields, :field_names, :field_indexes, :variants
366
338
 
367
339
  def set_fields(fields_or_hash)
340
+ raise TypeError, 'can be set only once' if @fields
368
341
  fields, keys = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
369
342
  [fields_or_hash.first.values, fields_or_hash.first.keys]
370
343
  else
@@ -380,16 +353,25 @@ module Algebrick
380
353
  @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
381
354
  end
382
355
 
383
- def set_field_names(names)
384
- @field_names = names
385
- names.all? { |k| is_kind_of! k, Symbol }
386
- dict = @field_indexes =
387
- Hash.new { |h, k| raise ArgumentError, "uknown field #{k.inspect}" }.
388
- update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
389
- define_method(:[]) { |key| @fields[dict[key]] }
356
+ def add_field_method_accessor(field)
357
+ raise TypeError, 'no field names' unless @field_names
358
+ raise ArgumentError, "no field name #{field}" unless @field_names.include? field
359
+ raise ArgumentError, "method #{field} already defined" if instance_methods.include? field
360
+ define_method(field) { self[field] }
361
+ self
362
+ end
363
+
364
+ def add_field_method_accessors(*fields)
365
+ fields.each { |f| add_field_method_accessor f }
366
+ self
367
+ end
368
+
369
+ def add_all_field_method_accessors
370
+ add_field_method_accessors *@field_names
390
371
  end
391
372
 
392
373
  def set_variants(variants)
374
+ raise TypeError, 'can be set only once' if @variants
393
375
  variants.all? { |v| is_kind_of! v, Type, Class }
394
376
  @variants = variants
395
377
  variants.each do |v|
@@ -401,14 +383,91 @@ module Algebrick
401
383
  end
402
384
  end
403
385
 
404
- def product_be_kind_of(type)
405
- @constructor.send :include, type
386
+ def new(*fields)
387
+ raise TypeError unless @constructor
388
+ @constructor.new *fields
406
389
  end
407
390
 
408
- def construct_product(*fields)
409
- @constructor.new *fields
391
+ alias_method :[], :new
392
+
393
+ def ==(other)
394
+ other.kind_of? ProductVariant and
395
+ variants == other.variants and fields == other.fields
410
396
  end
411
397
 
398
+ def be_kind_of(type)
399
+ kind
400
+ @constructor.send :include, type if @constructor
401
+ variants.each { |v| v.be_kind_of type unless v == self } if @variants
402
+ end
403
+
404
+ def call(*field_matchers)
405
+ raise TypeError unless @fields
406
+ Matchers::Product.new self, *field_matchers
407
+ end
408
+
409
+ def to_m
410
+ case kind
411
+ when :product
412
+ Matchers::Product.new self
413
+ when :product_variant
414
+ Matchers::Variant.new self
415
+ when :variant
416
+ Matchers::Variant.new self
417
+ else
418
+ raise
419
+ end
420
+ end
421
+
422
+ def to_s
423
+ case kind
424
+ when :product
425
+ product_to_s
426
+ when :product_variant
427
+ name + '(' +
428
+ variants.map do |variant|
429
+ if variant == self
430
+ product_to_s
431
+ else
432
+ variant.name
433
+ end
434
+ end.join(' | ') +
435
+ ')'
436
+ when :variant
437
+ "#{name}(#{variants.map(&:name).join ' | '})"
438
+ else
439
+ raise
440
+ end
441
+ end
442
+
443
+ def from_hash(hash)
444
+ case kind
445
+ when :product
446
+ product_from_hash hash
447
+ when :product_variant
448
+ product_from_hash hash
449
+ when :variant
450
+ field_from_hash hash
451
+ else
452
+ raise
453
+ end
454
+ end
455
+
456
+ def kind
457
+ case
458
+ when @fields && !@variants
459
+ :product
460
+ when @fields && @variants
461
+ :product_variant
462
+ when !@fields && @variants
463
+ :variant
464
+ when !@fields && !@variants
465
+ raise TypeError, 'fields or variants have to be set'
466
+ end
467
+ end
468
+
469
+ private
470
+
412
471
  def product_to_s
413
472
  fields_str = if field_names
414
473
  field_names.zip(fields).map { |name, field| "#{name}: #{field.name}" }
@@ -418,6 +477,15 @@ module Algebrick
418
477
  "#{name}(#{fields_str.join ', '})"
419
478
  end
420
479
 
480
+ def set_field_names(names)
481
+ @field_names = names
482
+ names.all? { |k| is_kind_of! k, Symbol }
483
+ dict = @field_indexes =
484
+ Hash.new { |h, k| raise ArgumentError, "unknown field #{k.inspect} in #{self}" }.
485
+ update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
486
+ define_method(:[]) { |key| @fields[dict[key]] }
487
+ end
488
+
421
489
  def product_from_hash(hash)
422
490
  (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or
423
491
  raise ArgumentError, "hash does not have #{TYPE_KEY}"
@@ -457,122 +525,35 @@ module Algebrick
457
525
  end
458
526
  end
459
527
 
460
- class Product < AbstractProductVariant
461
- attr_reader :fields, :field_names, :field_indexes
462
-
463
- def initialize(*fields, &block)
464
- set_fields fields
465
- super(&block)
466
- end
467
-
468
- def new(*fields)
469
- construct_product(*fields)
470
- end
471
-
472
- alias_method :[], :new
473
-
474
- def be_kind_of!(type)
475
- product_be_kind_of type
476
- end
477
-
478
- def call(*field_matchers)
479
- Matchers::Product.new self, *field_matchers
480
- end
481
-
482
- def to_m
483
- call *::Array.new(fields.size) { Algebrick.any }
484
- end
528
+ class TypeDefinitionScope
529
+ attr_reader :new_type
485
530
 
486
- def ==(other)
487
- other.kind_of? Product and fields == other.fields
488
- end
489
-
490
- def to_s
491
- product_to_s
492
- end
493
-
494
- def from_hash(hash)
495
- product_from_hash hash
496
- end
497
- end
498
-
499
- class Variant < AbstractProductVariant
500
- attr_reader :variants
501
-
502
- def initialize(*variants, &block)
503
- set_variants(variants)
504
- super &block
505
- end
506
-
507
- def be_kind_of!(type)
508
- variants.each { |v| v.be_kind_of type }
509
- end
510
-
511
- def to_m
512
- Matchers::Variant.new self
531
+ def initialize(&block)
532
+ @new_type = ProductVariant.new nil
533
+ instance_exec @new_type, &block
534
+ @new_type.kind
513
535
  end
514
536
 
515
- def ==(other)
516
- other.kind_of? Variant and variants == other.variants
537
+ def fields(*fields)
538
+ @new_type.set_fields fields
539
+ self
517
540
  end
518
541
 
519
- def to_s
520
- "#{name}(#{variants.map(&:name).join ' | '})"
542
+ def variants(*variants)
543
+ @new_type.set_variants variants
544
+ self
521
545
  end
522
546
 
523
- def from_hash(hash)
524
- field_from_hash hash
547
+ def type(&block)
548
+ Algebrick.type &block
525
549
  end
526
550
  end
527
551
 
528
- class ProductVariant < AbstractProductVariant
529
- attr_reader :fields, :field_names, :field_indexes, :variants
530
-
531
- def initialize(fields, variants, &block)
532
- set_fields fields
533
- raise unless variants.include? self
534
- set_variants variants
535
- super &block
536
- end
537
-
538
- def be_kind_of!(type)
539
- variants.each { |v| v.be_kind_of type unless v == self }
540
- product_be_kind_of type
541
- end
542
-
543
- def call(*field_matchers)
544
- Matchers::Product.new self, *field_matchers
545
- end
546
-
547
- def to_m
548
- Matchers::Variant.new self
549
- end
550
-
551
- def new(*fields)
552
- construct_product(*fields)
553
- end
554
-
555
- alias_method :[], :new
556
-
557
- def ==(other)
558
- other.kind_of? ProductVariant and
559
- variants == other.variants and fields == other.fields
560
- end
561
-
562
- def to_s
563
- name + '(' +
564
- variants.map do |variant|
565
- if variant == self
566
- product_to_s
567
- else
568
- variant.name
569
- end
570
- end.join(' | ') +
571
- ')'
572
- end
573
-
574
- def from_hash(hash)
575
- product_from_hash hash
552
+ def self.type(&block)
553
+ if block.nil?
554
+ Atom.new nil
555
+ else
556
+ TypeDefinitionScope.new(&block).new_type
576
557
  end
577
558
  end
578
559
 
@@ -583,26 +564,27 @@ module Algebrick
583
564
  attr_reader :value
584
565
 
585
566
  def initialize
586
- @assign, @value = nil
567
+ @assign, @value, @matched = nil
587
568
  end
588
569
 
589
570
  def case(&block)
590
571
  return self, block
591
572
  end
592
573
 
574
+ raise 'remove deprecation' if Algebrick.version >= Gem::Version.new('0.3')
575
+
593
576
  def -(block)
594
- return self, block
577
+ warn "a 'matcher --> {}' and 'matcher +-> {}' is deprecated, it'll be removed in 0.3\n#{caller[0]}"
578
+ self > block
595
579
  end
596
580
 
597
- alias_method :>>, :-
598
-
599
- raise 'remove deprecation' if Algebrick.version >= Gem::Version.new('0.2')
600
-
601
- def +(block)
602
- warn 'a_matcher +-> {} is deprecated, it\'ll be removed in 0.2'
603
- self - block
581
+ def >(block)
582
+ return self, block
604
583
  end
605
584
 
585
+ alias_method :>>, :>
586
+ alias_method :+, :-
587
+
606
588
  def ~
607
589
  @assign = true
608
590
  self
@@ -620,16 +602,23 @@ module Algebrick
620
602
  Not.new self
621
603
  end
622
604
 
605
+ def ^(matcher)
606
+ Xor.new self, matcher
607
+ end
608
+
623
609
  def assign?
624
610
  @assign
625
611
  end
626
612
 
613
+ def matched?
614
+ @matched
615
+ end
616
+
627
617
  def children_including_self
628
618
  children.unshift self
629
619
  end
630
620
 
631
621
  def assigns
632
- mine = @assign && @value ? [@value] : []
633
622
  mine = @assign ? [@value] : []
634
623
  children.inject(mine) { |assigns, child| assigns + child.assigns }.tap do
635
624
  return yield *assigns if block_given?
@@ -637,7 +626,7 @@ module Algebrick
637
626
  end
638
627
 
639
628
  def ===(other)
640
- matching?(other).tap { |matched| @value = other if matched }
629
+ matching?(other).tap { |matched| @value = other if (@matched = matched) }
641
630
  end
642
631
 
643
632
  def assign_to_s
@@ -725,6 +714,33 @@ module Algebrick
725
714
  end
726
715
  end
727
716
 
717
+ class Xor < Or
718
+ def to_s
719
+ matchers.join ' ^ '
720
+ end
721
+
722
+ alias_method :super_children, :children
723
+ private :super_children
724
+
725
+ def children
726
+ super.select &:matched?
727
+ end
728
+
729
+ def assigns
730
+ super.tap do |assigns|
731
+ missing = assigns_size - assigns.size
732
+ assigns.push(*::Array.new(missing))
733
+ end
734
+ end
735
+
736
+ private
737
+
738
+ def assigns_size
739
+ # TODO is it efficient?
740
+ super_children.map { |ch| ch.assigns.size }.max
741
+ end
742
+ end
743
+
728
744
  class Not < Abstract
729
745
  attr_reader :matcher
730
746
 
@@ -854,13 +870,14 @@ module Algebrick
854
870
  # TODO Method matcher (:size, matcher)
855
871
 
856
872
  class Product < Abstract
873
+ # TODO allow to match by field_name e.g. Address.(:street)
857
874
  attr_reader :algebraic_type, :field_matchers
858
875
 
859
876
  def initialize(algebraic_type, *field_matchers)
860
877
  super()
861
- is_kind_of! algebraic_type, Algebrick::Product, Algebrick::ProductVariant
862
- @algebraic_type = algebraic_type
863
- field_matchers += ::Array.new(algebraic_type.fields.size) { Algebrick.any } if field_matchers.empty?
878
+ @algebraic_type = is_kind_of! algebraic_type, Algebrick::ProductVariant
879
+ raise ArgumentError unless algebraic_type.fields
880
+ field_matchers += ::Array.new(algebraic_type.fields.size) { Algebrick.any } if field_matchers.empty?
864
881
  @field_matchers = field_matchers
865
882
  raise ArgumentError unless algebraic_type.fields.size == field_matchers.size
866
883
  end
@@ -891,7 +908,8 @@ module Algebrick
891
908
 
892
909
  class Variant < Wrapper
893
910
  def initialize(something)
894
- is_kind_of! something, Algebrick::Variant, Algebrick::ProductVariant
911
+ raise ArgumentError unless something.variants
912
+ is_kind_of! something, Algebrick::ProductVariant
895
913
  super something
896
914
  end
897
915
 
@@ -912,161 +930,565 @@ module Algebrick
912
930
  end
913
931
  end
914
932
 
915
- module DSL
916
- class PreType
917
- attr_reader :environment, :name, :fields, :variants, :definition
918
-
919
- def initialize(environment, name)
920
- @environment = environment
921
- @name = name
922
- @fields = []
923
- @variants = nil
924
- @definition = nil
925
- end
926
-
927
- def |(other)
928
- [self, other]
929
- end
930
-
931
- def to_ary
932
- [self]
933
- end
934
-
935
- def fields=(fields)
936
- raise unless @fields.empty?
937
- @fields += fields
938
- end
939
-
940
- def definition=(block)
941
- raise if @definition
942
- @definition = block
943
- end
944
-
945
- def is(variants)
946
- raise if @variants
947
- @variants = variants
948
- self
949
- end
950
-
951
- alias_method :===, :is
952
-
953
- def kind
954
- if @variants
955
- if @fields.empty?
956
- Variant
957
- else
958
- ProductVariant
959
- end
960
- else
961
- if @fields.empty?
962
- Atom
963
- else
964
- Product
965
- end
966
- end
967
- end
968
- end
969
-
970
- class Environment
971
- attr_reader :pre_types
972
- def initialize(base, &definition)
973
- @base = if base.is_a?(Object) && base.to_s == 'main'
974
- Object
975
- else
976
- base
977
- end
978
- @pre_types = {}
979
- instance_eval &definition
980
- end
981
-
982
- def method_missing(method, *fields, &definition)
983
- const_name = method.to_s.split('_').map { |s| s[0] = s[0].upcase; s }.join
984
-
985
- @pre_types[const_name] ||= PreType.new(self, const_name)
986
- @pre_types[const_name].fields = fields unless fields.empty?
987
- @pre_types[const_name].definition = definition if definition
988
- @pre_types[const_name]
989
- end
990
-
991
- def run
992
- define_constants
993
- define_fields_and_variants
994
- eval_definitions
995
- @pre_types.map { |name, _| get_class name }
996
- end
997
-
998
- private
999
-
1000
- def define_constants
1001
- @pre_types.each do |name, pre_type|
1002
- type = pre_type.kind.allocate
1003
- if @base.const_defined? name
1004
- defined = @base.const_get(name)
1005
- # #unless defined == type
1006
- raise "#{name} already defined as #{defined}"
1007
- # #end
1008
- else
1009
- #puts "defining #{name.to_sym.inspect} in #{@base}"
1010
- @base.const_set name.to_sym, type
1011
- end
1012
- end
1013
- end
1014
-
1015
- def define_fields_and_variants
1016
- select = ->(klass, &block) do
1017
- @pre_types.select { |_, pre_type| pre_type.kind == klass }.
1018
- map { |name, pre_type| [name, get_class(name), pre_type] }.
1019
- each &block
1020
- end
1021
-
1022
- select.(Atom) do |name, type, pre_type|
1023
- type.send :initialize
1024
- end
1025
-
1026
- select.(Product) do |name, type, pre_type|
1027
- type.send :initialize, *pre_type.fields.map { |f| get_class f }
1028
- end
1029
-
1030
- select.(Variant) do |name, type, pre_type|
1031
- type.send :initialize, *pre_type.variants.map { |v| get_class v }
1032
- end
1033
-
1034
- select.(ProductVariant) do |name, type, pre_type|
1035
- type.send :initialize,
1036
- pre_type.fields.map { |f| get_class f },
1037
- pre_type.variants.map { |v| get_class v }
1038
- end
1039
- end
1040
-
1041
- def eval_definitions
1042
- @pre_types.each do |name, pre_type|
1043
- next unless pre_type.definition
1044
- type = get_class name
1045
- type.module_eval &pre_type.definition
1046
- end
1047
- end
1048
-
1049
- def get_class(key)
1050
- if key.kind_of? String
1051
- @base.const_get key
1052
- elsif key.kind_of? PreType
1053
- @base.const_get key.name
1054
- elsif key.kind_of? Hash
1055
- key.each { |k, v| key[k] = get_class v }
1056
- else
1057
- key
1058
- end
1059
- end
1060
- end
1061
-
1062
- def type_def(base = self, &definition)
1063
- Environment.new(base, &definition).run
1064
- end
1065
- end
1066
-
1067
- extend DSL
1068
-
1069
- def self.type_def(base, &definition)
1070
- super base, &definition
1071
- end
933
+ #class AbstractProductVariant < Type
934
+ # def be_kind_of(type = nil)
935
+ # if initialized?
936
+ # be_kind_of! type if type
937
+ # if @to_be_kind_of
938
+ # while (type = @to_be_kind_of.shift)
939
+ # be_kind_of! type
940
+ # end
941
+ # end
942
+ # else
943
+ # @to_be_kind_of ||= []
944
+ # @to_be_kind_of << type if type
945
+ # end
946
+ # self
947
+ # end
948
+ #
949
+ # def add_field_method_accessor(field)
950
+ # raise TypeError, 'no field names' unless @field_names
951
+ # raise TypeError, "no field name #{field}" unless @field_names.include? field
952
+ # define_method(field) { self[field] }
953
+ # self
954
+ # end
955
+ #
956
+ # def add_field_method_accessors(*fields)
957
+ # fields.each { |f| add_field_method_accessor f }
958
+ # self
959
+ # end
960
+ #
961
+ # def add_all_field_method_accessors
962
+ # add_field_method_accessors *@field_names
963
+ # end
964
+ #
965
+ # protected
966
+ #
967
+ # def be_kind_of!(type)
968
+ # raise NotImplementedError
969
+ # end
970
+ #
971
+ # private
972
+ #
973
+ # def initialized?
974
+ # !!@initialized
975
+ # end
976
+ #
977
+ # def initialize(name, &block)
978
+ # super name, &block
979
+ # @initialized = true
980
+ # be_kind_of
981
+ # end
982
+ #
983
+ # def set_fields(fields_or_hash)
984
+ # fields, keys = if fields_or_hash.size == 1 && fields_or_hash.first.is_a?(Hash)
985
+ # [fields_or_hash.first.values, fields_or_hash.first.keys]
986
+ # else
987
+ # [fields_or_hash, nil]
988
+ # end
989
+ #
990
+ # set_field_names keys if keys
991
+ #
992
+ # fields.all? { |f| is_kind_of! f, Type, Class }
993
+ # raise TypeError, 'there is no product with zero fields' unless fields.size > 0
994
+ # define_method(:value) { @fields.first } if fields.size == 1
995
+ # @fields = fields
996
+ # @constructor = Class.new(ProductConstructor).tap { |c| c.type = self }
997
+ # end
998
+ #
999
+ # def set_field_names(names)
1000
+ # @field_names = names
1001
+ # names.all? { |k| is_kind_of! k, Symbol }
1002
+ # dict = @field_indexes =
1003
+ # Hash.new { |h, k| raise ArgumentError, "unknown field #{k.inspect} in #{self}" }.
1004
+ # update names.each_with_index.inject({}) { |h, (k, i)| h.update k => i }
1005
+ # define_method(:[]) { |key| @fields[dict[key]] }
1006
+ # end
1007
+ #
1008
+ # def set_variants(variants)
1009
+ # variants.all? { |v| is_kind_of! v, Type, Class }
1010
+ # @variants = variants
1011
+ # variants.each do |v|
1012
+ # if v.respond_to? :be_kind_of
1013
+ # v.be_kind_of self
1014
+ # else
1015
+ # v.send :include, self
1016
+ # end
1017
+ # end
1018
+ # end
1019
+ #
1020
+ # def product_be_kind_of(type)
1021
+ # @constructor.send :include, type
1022
+ # end
1023
+ #
1024
+ # def construct_product(*fields)
1025
+ # @constructor.new *fields
1026
+ # end
1027
+ #
1028
+ # def product_to_s
1029
+ # fields_str = if field_names
1030
+ # field_names.zip(fields).map { |name, field| "#{name}: #{field.name}" }
1031
+ # else
1032
+ # fields.map(&:name)
1033
+ # end
1034
+ # "#{name}(#{fields_str.join ', '})"
1035
+ # end
1036
+ #
1037
+ # def product_from_hash(hash)
1038
+ # (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or
1039
+ # raise ArgumentError, "hash does not have #{TYPE_KEY}"
1040
+ # raise ArgumentError, "#{type_name} is not #{name}" unless type_name == name
1041
+ #
1042
+ # fields = hash[FIELDS_KEY] || hash[FIELDS_KEY.to_s] ||
1043
+ # hash.reject { |k, _| k.to_s == TYPE_KEY.to_s }
1044
+ # is_kind_of! fields, Hash, Array
1045
+ #
1046
+ # case fields
1047
+ # when Array
1048
+ # self[*fields.map { |value| field_from_hash value }]
1049
+ # when Hash
1050
+ # self[fields.inject({}) do |h, (name, value)|
1051
+ # raise ArgumentError unless @field_names.map(&:to_s).include? name.to_s
1052
+ # h.update name.to_sym => field_from_hash(value)
1053
+ # end]
1054
+ # end
1055
+ # end
1056
+ #
1057
+ # def field_from_hash(hash)
1058
+ # return hash unless Hash === hash
1059
+ # (type_name = hash[TYPE_KEY] || hash[TYPE_KEY.to_s]) or return hash
1060
+ # type = constantize type_name
1061
+ # type.from_hash hash
1062
+ # end
1063
+ #
1064
+ # def constantize(camel_cased_word)
1065
+ # names = camel_cased_word.split('::')
1066
+ # names.shift if names.empty? || names.first.empty?
1067
+ #
1068
+ # constant = Object
1069
+ # names.each do |name|
1070
+ # constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
1071
+ # end
1072
+ # constant
1073
+ # end
1074
+ #end
1075
+ #
1076
+ #class Product < AbstractProductVariant
1077
+ # attr_reader :fields, :field_names, :field_indexes
1078
+ #
1079
+ # def initialize(name, *fields, &block)
1080
+ # set_fields fields
1081
+ # super(name, &block)
1082
+ # end
1083
+ #
1084
+ # def new(*fields)
1085
+ # construct_product(*fields)
1086
+ # end
1087
+ #
1088
+ # alias_method :[], :new
1089
+ #
1090
+ # def be_kind_of!(type)
1091
+ # product_be_kind_of type
1092
+ # end
1093
+ #
1094
+ # def call(*field_matchers)
1095
+ # Matchers::Product.new self, *field_matchers
1096
+ # end
1097
+ #
1098
+ # def to_m
1099
+ # call *::Array.new(fields.size) { Algebrick.any }
1100
+ # end
1101
+ #
1102
+ # def ==(other)
1103
+ # other.kind_of? Product and fields == other.fields
1104
+ # end
1105
+ #
1106
+ # def to_s
1107
+ # product_to_s
1108
+ # end
1109
+ #
1110
+ # def from_hash(hash)
1111
+ # product_from_hash hash
1112
+ # end
1113
+ #end
1114
+ #
1115
+ #class Variant < AbstractProductVariant
1116
+ # attr_reader :variants
1117
+ #
1118
+ # def initialize(name, *variants, &block)
1119
+ # set_variants(variants)
1120
+ # super name, &block
1121
+ # end
1122
+ #
1123
+ # def be_kind_of!(type)
1124
+ # variants.each { |v| v.be_kind_of type }
1125
+ # end
1126
+ #
1127
+ # def to_m
1128
+ # Matchers::Variant.new self
1129
+ # end
1130
+ #
1131
+ # def ==(other)
1132
+ # other.kind_of? Variant and variants == other.variants
1133
+ # end
1134
+ #
1135
+ # def to_s
1136
+ # "#{name}(#{variants.map(&:name).join ' | '})"
1137
+ # end
1138
+ #
1139
+ # def from_hash(hash)
1140
+ # field_from_hash hash
1141
+ # end
1142
+ #end
1143
+ #
1144
+ #class ProductVariant < AbstractProductVariant
1145
+ # attr_reader :fields, :field_names, :field_indexes, :variants
1146
+ #
1147
+ # def initialize(name, fields, variants, &block)
1148
+ # set_fields fields
1149
+ # raise unless variants.include? self
1150
+ # set_variants variants
1151
+ # super name, &block
1152
+ # end
1153
+ #
1154
+ # def be_kind_of!(type)
1155
+ # variants.each { |v| v.be_kind_of type unless v == self }
1156
+ # product_be_kind_of type
1157
+ # end
1158
+ #
1159
+ # def call(*field_matchers)
1160
+ # Matchers::Product.new self, *field_matchers
1161
+ # end
1162
+ #
1163
+ # def to_m
1164
+ # Matchers::Variant.new self
1165
+ # end
1166
+ #
1167
+ # def new(*fields)
1168
+ # construct_product(*fields)
1169
+ # end
1170
+ #
1171
+ # alias_method :[], :new
1172
+ #
1173
+ # def ==(other)
1174
+ # other.kind_of? ProductVariant and
1175
+ # variants == other.variants and fields == other.fields
1176
+ # end
1177
+ #
1178
+ # def to_s
1179
+ # name + '(' +
1180
+ # variants.map do |variant|
1181
+ # if variant == self
1182
+ # product_to_s
1183
+ # else
1184
+ # variant.name
1185
+ # end
1186
+ # end.join(' | ') +
1187
+ # ')'
1188
+ # end
1189
+ #
1190
+ # def from_hash(hash)
1191
+ # product_from_hash hash
1192
+ # end
1193
+ #end
1194
+
1195
+ #module DSL
1196
+ # -> do
1197
+ # maybe[:a] === none | some(:a)
1198
+ # tree[:a] === tip | tree(:a, tree, tree)
1199
+ # end
1200
+ #
1201
+ # -> do
1202
+ # maybe[:a].can_be none,
1203
+ # some.has(:a)
1204
+ #
1205
+ # maybe[:a].can_be none,
1206
+ # some.having(:a)
1207
+ #
1208
+ # maybe[:a].can_be none,
1209
+ # some.having(:a)
1210
+ # tree.can_be tip,
1211
+ # tree.having(Object, tree, tree)
1212
+ #
1213
+ # tree.can_be empty,
1214
+ # leaf.having(Object),
1215
+ # node.having(left: tree, right: tree)
1216
+ #
1217
+ # tree do
1218
+ # # def ...
1219
+ # end
1220
+ # end
1221
+ #
1222
+ # class PreType
1223
+ # include TypeCheck
1224
+ #
1225
+ # attr_reader :environment, :name, :fields, :variants, :definition, :variables
1226
+ #
1227
+ # def initialize(environment, name)
1228
+ # @environment = is_kind_of! environment, Environment
1229
+ # @name = is_kind_of! name, String
1230
+ # @fields = []
1231
+ # @variables = []
1232
+ # @variants = []
1233
+ # @definition = nil
1234
+ # end
1235
+ #
1236
+ # def const_name
1237
+ # @const_name ||= name.to_s.split('_').map { |s| s.tap { s[0] = s[0].upcase } }.join
1238
+ # end
1239
+ #
1240
+ # #def |(other)
1241
+ # # [self, other]
1242
+ # #end
1243
+ # #
1244
+ # #def to_ary
1245
+ # # [self]
1246
+ # #end
1247
+ #
1248
+ # def [](*variables)
1249
+ # variables.all? { |var| is_kind_of! var, Symbol }
1250
+ # @variables += variables
1251
+ # self
1252
+ # end
1253
+ #
1254
+ # def fields=(fields)
1255
+ # raise 'fields can be defined only once' unless @fields.empty?
1256
+ # fields.each do |field|
1257
+ # if Hash === field
1258
+ # field.each do |k, v|
1259
+ # is_kind_of! k, Symbol
1260
+ # is_kind_of! v, PreType, Type, Class, Symbol
1261
+ # @variables.push v if v.is_a? Symbol
1262
+ # end
1263
+ # else
1264
+ # is_kind_of! field, PreType, Type, Class, Symbol
1265
+ # @variables += fields.select { |v| v.is_a? Symbol }
1266
+ # end
1267
+ # end
1268
+ # @fields += fields
1269
+ # end
1270
+ #
1271
+ # def having(fields)
1272
+ # self.fields = fields
1273
+ # self
1274
+ # end
1275
+ #
1276
+ # alias_method :has, :having
1277
+ #
1278
+ # def fields_array
1279
+ # if (hash = @fields.find { |f| Hash === f })
1280
+ # hash.values
1281
+ # else
1282
+ # @fields
1283
+ # end
1284
+ # end
1285
+ #
1286
+ # #def dependent(set = Set.new)
1287
+ # # children = @variants + @fields
1288
+ # # children.each do |a_type|
1289
+ # # next if set.include? a_type
1290
+ # # next unless a_type.respond_to? :dependent
1291
+ # # set.add a_type
1292
+ # # a_type.dependent set
1293
+ # # end
1294
+ # # set.to_a
1295
+ # #end
1296
+ #
1297
+ # def definition=(block)
1298
+ # raise 'definition can be defined only once' if @definition
1299
+ # @definition = block
1300
+ # end
1301
+ #
1302
+ # def can_be(*variants)
1303
+ # raise 'variants can be defined only once' unless @variants.empty?
1304
+ # @variants = variants
1305
+ # self
1306
+ # end
1307
+ #
1308
+ # def no_variables?
1309
+ # !variables? and fields_array.select { |f| Symbol === f }.empty?
1310
+ # end
1311
+ #
1312
+ # def variables?
1313
+ # not @variables.empty?
1314
+ # end
1315
+ #
1316
+ # def kind
1317
+ # unless @variants.empty?
1318
+ # if @fields.empty?
1319
+ # Variant
1320
+ # else
1321
+ # ProductVariant
1322
+ # end
1323
+ # else
1324
+ # if @fields.empty?
1325
+ # Atom
1326
+ # else
1327
+ # Product
1328
+ # end
1329
+ # end
1330
+ # end
1331
+ # end
1332
+ #
1333
+ # class TypeConstructor
1334
+ # include TypeCheck
1335
+ # attr_reader :const_name
1336
+ #
1337
+ # def initialize(pre_types, const_name, variables)
1338
+ # warn "types with variables are experimental\n#{caller[0]}"
1339
+ # @pre_types = is_kind_of! pre_types, Hash
1340
+ # @const_name = is_kind_of! const_name, String
1341
+ # @variables = is_kind_of! variables, Array
1342
+ # @cache = {}
1343
+ # end
1344
+ #
1345
+ # def [](*variables)
1346
+ # variables.size == @variables.size or
1347
+ # raise ArgumentError, "variables size differs from #{@variables}"
1348
+ # @cache[variables] ||= begin
1349
+ #
1350
+ # TypeFactory.new(@pre_types, Hash[@variables.zip(variables)]).define.tap do |types|
1351
+ # types.each do |name, type|
1352
+ #
1353
+ # end
1354
+ # end
1355
+ # end
1356
+ # end
1357
+ #
1358
+ # def to_s
1359
+ # const_name + @variables.inspect
1360
+ # end
1361
+ #
1362
+ # def inspect
1363
+ # to_s
1364
+ # end
1365
+ # end
1366
+ #
1367
+ # class TypeFactory
1368
+ # include TypeCheck
1369
+ #
1370
+ # def initialize(pre_types, variable_mapping)
1371
+ # @pre_types = is_kind_of! pre_types, Hash
1372
+ # @variable_mapping = is_kind_of! variable_mapping, Hash
1373
+ # @types = {}
1374
+ # end
1375
+ #
1376
+ # def define
1377
+ # define_types
1378
+ # define_fields_and_variants
1379
+ # eval_definitions
1380
+ #
1381
+ # @types
1382
+ # end
1383
+ #
1384
+ # private
1385
+ #
1386
+ # def define_types
1387
+ # @pre_types.each do |name, pre_type|
1388
+ # @types[name] = pre_type.kind.allocate
1389
+ # end
1390
+ # end
1391
+ #
1392
+ # def define_fields_and_variants
1393
+ # select = ->(klass, &block) do
1394
+ # @pre_types.select { |_, pre_type| pre_type.kind == klass }.each &block
1395
+ # end
1396
+ #
1397
+ # select.(Atom) do |name, pre_type|
1398
+ # @types[name].send :initialize, type_name(pre_type)
1399
+ # end
1400
+ #
1401
+ # select.(Product) do |name, pre_type|
1402
+ # @types[name].send :initialize, type_name(pre_type), *pre_type.fields.map { |f| get_class f }
1403
+ # end
1404
+ #
1405
+ # select.(Variant) do |name, pre_type|
1406
+ # @types[name].send :initialize, type_name(pre_type), *pre_type.variants.map { |v| get_class v }
1407
+ # end
1408
+ #
1409
+ # select.(ProductVariant) do |name, pre_type|
1410
+ # @types[name].send :initialize, type_name(pre_type),
1411
+ # pre_type.fields.map { |f| get_class f },
1412
+ # pre_type.variants.map { |v| get_class v }
1413
+ # end
1414
+ # end
1415
+ #
1416
+ # def eval_definitions
1417
+ # @pre_types.each do |name, pre_type|
1418
+ # next unless pre_type.definition
1419
+ # type = get_class name
1420
+ # type.module_eval &pre_type.definition
1421
+ # end
1422
+ # end
1423
+ #
1424
+ # def get_class(key)
1425
+ # if key.kind_of? Symbol
1426
+ # @variable_mapping[key] or raise "missing variable mapping for #{key}"
1427
+ # elsif key.kind_of? String
1428
+ # @types[key] or raise ArgumentError
1429
+ # elsif key.kind_of? PreType
1430
+ # @types[key.name]
1431
+ # elsif key.kind_of? Hash
1432
+ # key.each { |k, v| key[k] = get_class v }
1433
+ # else
1434
+ # key
1435
+ # end
1436
+ # end
1437
+ #
1438
+ # def type_name(pre_type)
1439
+ # pre_type.const_name + if pre_type.variables?
1440
+ # '[' + pre_type.variables.map { |v| @variable_mapping[v] } * ',' + ']'
1441
+ # else
1442
+ # ''
1443
+ # end
1444
+ # end
1445
+ # end
1446
+ #
1447
+ # class Environment
1448
+ # attr_reader :pre_types
1449
+ # def initialize(&definition)
1450
+ # @pre_types = {}
1451
+ # @types = {}
1452
+ # instance_eval &definition
1453
+ # end
1454
+ #
1455
+ # def method_missing(method, *fields, &definition)
1456
+ # name = method.to_s
1457
+ # @pre_types[name] ||= PreType.new(self, name)
1458
+ # @pre_types[name].fields = fields unless fields.empty?
1459
+ # @pre_types[name].definition = definition if definition
1460
+ # @pre_types[name]
1461
+ # end
1462
+ #
1463
+ # def run
1464
+ # pre_types = @pre_types.select { |_, pt| pt.no_variables? }
1465
+ # types = TypeFactory.new(pre_types, {}).define
1466
+ # constants = pre_types.inject({}) do |hash, (name, pre_type)|
1467
+ # hash.update pre_type.const_name => types[name]
1468
+ # end
1469
+ #
1470
+ # pre_constructors = @pre_types.select { |_, pt| pt.variables? }
1471
+ # constructors = pre_constructors.inject({}) do |hash, (name, pt)|
1472
+ # pre_types = Hash[([pt] + pt.dependent).map { |pt| [pt.name, pt] }]
1473
+ # hash.update name => TypeConstructor.new(pre_types, pt.const_name, pt.variables)
1474
+ # end
1475
+ #
1476
+ # constants.update Hash[constructors.map { |name, c| [c.const_name, c] }]
1477
+ #
1478
+ # @pre_types.map { |name, pre_type| types[name] || constructors[name] || raise("missing #{name}") }
1479
+ # end
1480
+ #
1481
+ # private
1482
+ #
1483
+ # #def define_constants(map)
1484
+ # # map.each { |const_name, value| @base.const_set const_name.to_sym, value } if @base
1485
+ # #end
1486
+ # end
1487
+ #
1488
+ # def type_def(&definition)
1489
+ # Environment.new(&definition).run
1490
+ # end
1491
+ #end
1492
+
1493
+ #extend DSL
1072
1494
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: algebrick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Petr Chalupa