dhall 0.3.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ module Dhall
12
12
 
13
13
  def self.assert_type(expr, assertion, message, context:)
14
14
  aexpr = self.for(expr).annotate(context)
15
- type = aexpr.type
15
+ type = aexpr.type.normalize
16
16
  raise TypeError, "#{message}: #{type}" unless assertion === type
17
17
  aexpr
18
18
  end
@@ -20,7 +20,9 @@ module Dhall
20
20
  def self.assert_types_match(a, b, message, context:)
21
21
  atype = self.for(a).annotate(context).type
22
22
  btype = self.for(b).annotate(context).type
23
- raise TypeError, "#{message}: #{atype}, #{btype}" unless atype == btype
23
+ unless atype.normalize == btype.normalize
24
+ raise TypeError, "#{message}: #{atype}, #{btype}"
25
+ end
24
26
  atype
25
27
  end
26
28
 
@@ -40,9 +42,13 @@ module Dhall
40
42
  @typecheckers[node_type] ||= [typechecker, extras]
41
43
  end
42
44
 
43
- def self.type_of(expr)
45
+ def self.annotate(expr)
44
46
  return if expr.nil?
45
- TypeChecker.for(expr).annotate(TypeChecker::Context.new).type
47
+ TypeChecker.for(expr).annotate(TypeChecker::Context.new)
48
+ end
49
+
50
+ def self.type_of(expr)
51
+ annotate(expr)&.type
46
52
  end
47
53
 
48
54
  class Context
@@ -233,6 +239,31 @@ module Dhall
233
239
  end
234
240
  end
235
241
 
242
+ class OperatorEquivalent
243
+ TypeChecker.register self, Dhall::Operator::Equivalent
244
+
245
+ def initialize(expr)
246
+ @expr = expr
247
+ @lhs = expr.lhs
248
+ @rhs = expr.rhs
249
+ end
250
+
251
+ def annotate(context)
252
+ type = TypeChecker.assert_types_match @lhs, @rhs,
253
+ "arguments do not match",
254
+ context: context
255
+
256
+ TypeChecker.assert_type type, Builtins[:Type],
257
+ "arguments are not terms",
258
+ context: context
259
+
260
+ Dhall::TypeAnnotation.new(
261
+ value: @expr.with(lhs: @lhs.annotate(type), rhs: @rhs.annotate(type)),
262
+ type: Builtins[:Type]
263
+ )
264
+ end
265
+ end
266
+
236
267
  class OperatorListConcatenate
237
268
  TypeChecker.register self, Dhall::Operator::ListConcatenate
238
269
 
@@ -309,10 +340,6 @@ module Dhall
309
340
  "RecursiveRecordMerge got",
310
341
  context: context
311
342
 
312
- TypeChecker.assert_types_match annotated_lhs.type, annotated_rhs.type,
313
- "RecursiveRecordMerge got mixed kinds",
314
- context: context
315
-
316
343
  [annotated_lhs, annotated_rhs]
317
344
  end
318
345
 
@@ -336,12 +363,6 @@ module Dhall
336
363
  end
337
364
 
338
365
  def annotate(context)
339
- kind = TypeChecker.assert_types_match(
340
- @expr.lhs, @expr.rhs,
341
- "RecursiveRecordTypeMerge mixed kinds",
342
- context: context
343
- )
344
-
345
366
  type = @expr.lhs.deep_merge_type(@expr.rhs)
346
367
 
347
368
  TypeChecker.assert type, Dhall::RecordType,
@@ -350,7 +371,13 @@ module Dhall
350
371
  # Annotate to sanity check
351
372
  TypeChecker.for(type).annotate(context)
352
373
 
353
- Dhall::TypeAnnotation.new(value: @expr, type: kind)
374
+ Dhall::TypeAnnotation.new(value: @expr, type: kind(context))
375
+ end
376
+
377
+ def kind(context)
378
+ lhs_kind = KINDS.index(TypeChecker.for(@expr.lhs).annotate(context).type)
379
+ rhs_kind = KINDS.index(TypeChecker.for(@expr.rhs).annotate(context).type)
380
+ KINDS[[lhs_kind, rhs_kind].max]
354
381
  end
355
382
  end
356
383
 
@@ -358,10 +385,16 @@ module Dhall
358
385
  TypeChecker.register self, Dhall::EmptyList
359
386
 
360
387
  def initialize(expr)
361
- @expr = expr
388
+ @expr = expr.with(type: expr.type.normalize)
362
389
  end
363
390
 
364
391
  def annotate(context)
392
+ TypeChecker.assert @expr.type, Dhall::Application,
393
+ "EmptyList unknown type #{@expr.type.inspect}"
394
+
395
+ TypeChecker.assert @expr.type.function, Builtins[:List],
396
+ "EmptyList unknown type #{@expr.type.inspect}"
397
+
365
398
  TypeChecker.assert_type @expr.element_type, Builtins[:Type],
366
399
  "EmptyList element type not of type Type",
367
400
  context: context
@@ -383,7 +416,7 @@ module Dhall
383
416
  end
384
417
 
385
418
  def annotation
386
- list = @alist.with(element_type: element_type)
419
+ list = @alist.with(type: Builtins[:List].call(element_type))
387
420
  Dhall::TypeAnnotation.new(type: list.type, value: list)
388
421
  end
389
422
 
@@ -468,13 +501,20 @@ module Dhall
468
501
 
469
502
  class AnonymousType
470
503
  TypeChecker.register self, Dhall::RecordType
471
- TypeChecker.register self, Dhall::UnionType
472
504
 
473
505
  def initialize(type)
474
506
  @type = type
475
507
  end
476
508
 
477
509
  def annotate(context)
510
+ kinds = check(context)
511
+ type = kinds.max_by { |k| KINDS.index(k) } || KINDS.first
512
+ Dhall::TypeAnnotation.new(value: @type, type: type)
513
+ end
514
+
515
+ protected
516
+
517
+ def check(context)
478
518
  kinds = @type.record.values.compact.map do |mtype|
479
519
  TypeChecker.for(mtype).annotate(context).type
480
520
  end
@@ -482,6 +522,16 @@ module Dhall
482
522
  TypeChecker.assert (kinds - KINDS), [],
483
523
  "AnonymousType field kind not one of #{KINDS}"
484
524
 
525
+ kinds
526
+ end
527
+ end
528
+
529
+ class UnionType < AnonymousType
530
+ TypeChecker.register self, Dhall::UnionType
531
+
532
+ def annotate(context)
533
+ kinds = check(context)
534
+
485
535
  TypeChecker.assert kinds, Util::ArrayAllTheSame,
486
536
  "AnonymousType field kinds not all the same"
487
537
 
@@ -537,12 +587,13 @@ module Dhall
537
587
 
538
588
  class Selector
539
589
  def self.for(annotated_record)
540
- if annotated_record.type == Builtins[:Type]
590
+ typ = annotated_record.type.normalize
591
+ if KINDS.include?(typ)
541
592
  TypeSelector.new(annotated_record.value)
542
- elsif annotated_record.type.class == Dhall::RecordType
543
- new(annotated_record.type)
593
+ elsif typ.class == Dhall::RecordType
594
+ new(typ)
544
595
  else
545
- raise TypeError, "RecordSelection on #{annotated_record.type}"
596
+ raise TypeError, "RecordSelection on #{typ}"
546
597
  end
547
598
  end
548
599
 
@@ -604,6 +655,33 @@ module Dhall
604
655
  end
605
656
  end
606
657
 
658
+ class RecordProjectionByExpression
659
+ TypeChecker.register self, Dhall::RecordProjectionByExpression
660
+
661
+ def initialize(projection)
662
+ @selector = projection.selector.normalize
663
+ @project_by_expression = projection
664
+ @project_by_keys = Dhall::RecordProjection.for(
665
+ @project_by_expression.record,
666
+ @selector.keys
667
+ )
668
+ end
669
+
670
+ def annotate(context)
671
+ TypeChecker.assert @selector, Dhall::RecordType,
672
+ "RecordProjectionByExpression on #{@selector.class}"
673
+
674
+ TypeChecker.assert_type @project_by_keys, @selector,
675
+ "Type doesn't match #{@selector}",
676
+ context: context
677
+
678
+ Dhall::TypeAnnotation.new(
679
+ value: @project_by_expression,
680
+ type: @selector
681
+ )
682
+ end
683
+ end
684
+
607
685
  class Enum
608
686
  TypeChecker.register self, Dhall::Enum
609
687
 
@@ -648,6 +726,39 @@ module Dhall
648
726
  end
649
727
  end
650
728
 
729
+ class ToMap
730
+ TypeChecker.register self, Dhall::ToMap
731
+
732
+ def initialize(tomap)
733
+ @tomap = tomap
734
+ @record = TypeChecker.for(tomap.record)
735
+ end
736
+
737
+ def check_annotation(record_type)
738
+ if record_type.is_a?(Dhall::EmptyRecordType)
739
+ TypeChecker.assert @tomap.type, Dhall::Expression,
740
+ "toMap {=} has no annotation"
741
+ else
742
+ t = Types::MAP(v: record_type.record.values.first)
743
+
744
+ TypeChecker.assert t, (@tomap.type || t),
745
+ "toMap does not match annotation"
746
+ end
747
+ end
748
+
749
+ def annotate(context)
750
+ record_type = @record.annotate(context).type
751
+ TypeChecker.assert record_type, Dhall::RecordType,
752
+ "toMap on a non-record: #{record_type.inspect}"
753
+
754
+ TypeChecker.assert record_type.record.values, Util::ArrayAllTheSame,
755
+ "toMap heterogenous: #{record_type.inspect}"
756
+
757
+ type = check_annotation(record_type)
758
+ Dhall::TypeAnnotation.new(value: @tomap, type: type)
759
+ end
760
+ end
761
+
651
762
  class Merge
652
763
  TypeChecker.register self, Dhall::Merge
653
764
 
@@ -678,7 +789,7 @@ module Dhall
678
789
  end
679
790
 
680
791
  def keys
681
- @type.record.keys
792
+ Set.new(@type.record.keys)
682
793
  end
683
794
 
684
795
  def fetch_input_type(k)
@@ -729,8 +840,8 @@ module Dhall
729
840
  end
730
841
 
731
842
  def assert_union_and_handlers_match
732
- extras = @handlers.keys - @union.type.alternatives.keys
733
- TypeChecker.assert extras, [],
843
+ extras = @handlers.keys ^ @union.type.alternatives.keys
844
+ TypeChecker.assert extras.to_a, [],
734
845
  "Merge handlers unknown alternatives: #{extras}"
735
846
 
736
847
  @union.type.alternatives.each do |k, atype|
@@ -771,8 +882,6 @@ module Dhall
771
882
  raise TypeError, "FunctionType part of this is a term"
772
883
  end
773
884
 
774
- raise TypeError, "Dependent types are not allowed" if outkind > inkind
775
-
776
885
  if outkind.zero?
777
886
  Term.new
778
887
  else
@@ -860,8 +969,6 @@ module Dhall
860
969
  end
861
970
  end
862
971
 
863
- TypeChecker.register ->(blk) { LetIn.for(blk.unflatten) }, Dhall::LetBlock
864
-
865
972
  class LetIn
866
973
  TypeChecker.register self, Dhall::LetIn
867
974
 
@@ -927,6 +1034,30 @@ module Dhall
927
1034
  end
928
1035
  end
929
1036
 
1037
+ class Assertion
1038
+ TypeChecker.register self, Dhall::Assertion
1039
+
1040
+ def initialize(expr)
1041
+ @expr = expr
1042
+ @type = expr.type
1043
+ end
1044
+
1045
+ def annotate(context)
1046
+ TypeChecker.assert @type, Dhall::Operator::Equivalent,
1047
+ "assert expected === got: #{@type.class}"
1048
+
1049
+ TypeChecker.assert_type @type, Builtins[:Type],
1050
+ "=== expected to have type Type",
1051
+ context: context
1052
+
1053
+ TypeChecker.assert @type.lhs.normalize.to_binary,
1054
+ @type.rhs.normalize.to_binary,
1055
+ "assert equivalence not equivalent"
1056
+
1057
+ @expr.with(type: @type.normalize)
1058
+ end
1059
+ end
1060
+
930
1061
  BUILTIN_TYPES = {
931
1062
  "Bool" => Builtins[:Type],
932
1063
  "Type" => Builtins[:Kind],
@@ -989,6 +1120,11 @@ module Dhall
989
1120
  )
990
1121
  )
991
1122
  ),
1123
+ "Natural/subtract" => Dhall::Forall.of_arguments(
1124
+ Builtins[:Natural],
1125
+ Builtins[:Natural],
1126
+ body: Builtins[:Natural]
1127
+ ),
992
1128
  "Natural/isZero" => Dhall::Forall.of_arguments(
993
1129
  Builtins[:Natural],
994
1130
  body: Builtins[:Bool]
@@ -1209,12 +1345,13 @@ module Dhall
1209
1345
  TypeChecker.register self, Dhall::Builtin
1210
1346
 
1211
1347
  def self.for(builtin)
1212
- unfilled = builtin.unfill
1213
- if unfilled != builtin
1214
- TypeChecker.for(unfilled)
1215
- else
1216
- new(builtin)
1348
+ if builtin.is_a?(Dhall::BuiltinFunction)
1349
+ if (unfilled = builtin.unfill) != builtin
1350
+ return TypeChecker.for(unfilled)
1351
+ end
1217
1352
  end
1353
+
1354
+ new(builtin)
1218
1355
  end
1219
1356
 
1220
1357
  def initialize(builtin)
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dhall/builtins"
4
+
5
+ module Dhall
6
+ module Types
7
+ def self.MAP_ENTRY(k: Builtins[:Text], v: Builtins[:Text])
8
+ RecordType.new(
9
+ record: {
10
+ "mapKey" => k, "mapValue" => v
11
+ }
12
+ )
13
+ end
14
+
15
+ def self.MAP(k: Builtins[:Text], v: Builtins[:Text])
16
+ Builtins[:List].call(MAP_ENTRY(k: k, v: v))
17
+ end
18
+ end
19
+ end
data/lib/dhall/util.rb CHANGED
@@ -1,9 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "promise"
3
4
  require "timeout"
4
5
 
5
6
  module Dhall
6
7
  module Util
8
+ class LazyPromise < Promise
9
+ def initialize(&block)
10
+ super
11
+ @block = block
12
+ end
13
+
14
+ def subscribe(*args)
15
+ super
16
+
17
+ begin
18
+ fulfill(@block.call)
19
+ rescue => e
20
+ reject(e)
21
+ end
22
+ end
23
+ end
24
+
7
25
  class AllOf
8
26
  def initialize(*validators)
9
27
  @validators = validators
@@ -181,5 +199,36 @@ module Dhall
181
199
  def self.longest_common_prefix(a, b)
182
200
  a.zip(b).take_while { |(x, y)| x == y }.map(&:first)
183
201
  end
202
+
203
+ def self.indent_size(str)
204
+ if str.end_with?("\n")
205
+ 0
206
+ else
207
+ str
208
+ .scan(/^[ \t]*(?=[^ \t\n]|\Z)/)
209
+ .map(&:chars)
210
+ .reduce(&method(:longest_common_prefix))&.length.to_i
211
+ end
212
+ end
213
+
214
+ def self.path_components_to_uri(*components)
215
+ URI("/#{components.map(&method(:uri_escape)).join("/")}")
216
+ end
217
+
218
+ def self.uri_escape(s)
219
+ ::URI.encode_www_form_component(s).gsub("+", "%20")
220
+ end
221
+
222
+ def self.net_http_req_with_timeout(uri, req, timeout:)
223
+ Net::HTTP.start(
224
+ uri.hostname,
225
+ uri.port,
226
+ use_ssl: uri.scheme == "https",
227
+ open_timeout: timeout,
228
+ ssl_timeout: timeout,
229
+ read_timeout: timeout,
230
+ write_timeout: timeout
231
+ ) { |http| http.request(req) }
232
+ end
184
233
  end
185
234
  end
data/lib/dhall.rb CHANGED
@@ -9,6 +9,7 @@ require "dhall/normalize"
9
9
  require "dhall/parser"
10
10
  require "dhall/resolve"
11
11
  require "dhall/typecheck"
12
+ require "dhall/types"
12
13
 
13
14
  module Dhall
14
15
  using Dhall::AsDhall
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Paul Weber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-13 00:00:00.000000000 Z
11
+ date: 2021-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: base32
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.3.2
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: cbor
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +52,34 @@ dependencies:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: lazy_object
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: multihashes
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.0
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: promise.rb
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +122,20 @@ dependencies:
80
122
  - - "~>"
81
123
  - !ruby/object:Gem::Version
82
124
  version: 0.0.1
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest-fail-fast
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.1.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.1.0
83
139
  - !ruby/object:Gem::Dependency
84
140
  name: simplecov
85
141
  requirement: !ruby/object:Gem::Requirement
@@ -137,8 +193,8 @@ files:
137
193
  - lib/dhall/parser.rb
138
194
  - lib/dhall/resolve.rb
139
195
  - lib/dhall/typecheck.rb
196
+ - lib/dhall/types.rb
140
197
  - lib/dhall/util.rb
141
- - lib/dhall/visitor.rb
142
198
  homepage: https://git.sr.ht/~singpolyma/dhall-ruby
143
199
  licenses:
144
200
  - GPL-3.0
@@ -159,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
215
  version: '0'
160
216
  requirements: []
161
217
  rubyforge_project:
162
- rubygems_version: 2.5.2.1
218
+ rubygems_version: 2.7.6.2
163
219
  signing_key:
164
220
  specification_version: 4
165
221
  summary: The non-repetitive alternative to YAML, in Ruby