dhall 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 55053ce451e1b675998712636c725380329d1fe6
4
- data.tar.gz: d98038e234871e81f8c0ce3f6d2a8f7c941b8278
3
+ metadata.gz: 7132b6745d968ae3d719249d6b996438b99b9a3f
4
+ data.tar.gz: 33c3de17c1b2dc921024f3fb14aeba7fb89624c9
5
5
  SHA512:
6
- metadata.gz: 4735802d9beb7c796d06ba6c887f5776ac24f12342ad754d911cc36593fb730f0c4d861b653b3667ad1590835014ffcf865e1aa4bd5a56f3c4d9b4e49274d808
7
- data.tar.gz: 386cda30b6cd93ea7b6236bab460681554240355e25609c4791cb7d85cf6ff07f3b6a3d6b2a3727c2d6d9d8c2123105b4bcf1a03f1cb0272baa2651b4c0c7159
6
+ metadata.gz: 89f23e3937ebe15c2a2b693ef5056802a4edc5ccb529ca37e9c8eb43f611b8f9477b722116c5ac143ec10c346c8e61e03f66b3d677984efb84214fbc9d7a45b4
7
+ data.tar.gz: 26fcce26e98bc480b6d14adaf482debe2ad99dac6d997af1352f6e5cf89dc8930ea3a2766857b984c023d07140c50b672e0635c33f8505820e325ec5bd5a21cf
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_dependency "value_semantics", "~> 3.0"
35
35
 
36
36
  spec.add_development_dependency "abnf", "~> 0.0.1"
37
+ spec.add_development_dependency "minitest-fail-fast", "~> 0.1.0"
37
38
  spec.add_development_dependency "simplecov", "~> 0.16.1"
38
39
  spec.add_development_dependency "webmock", "~> 3.5"
39
40
  end
@@ -104,6 +104,10 @@ module Dhall
104
104
  end
105
105
  end
106
106
 
107
+ def annotate(type)
108
+ TypeAnnotation.new(value: self, type: type)
109
+ end
110
+
107
111
  def to_s
108
112
  inspect
109
113
  end
@@ -347,6 +351,33 @@ module Dhall
347
351
  [3, OPERATORS.index(self.class), lhs.as_json, rhs.as_json]
348
352
  end
349
353
 
354
+ module FetchFromMerge
355
+ def fetch_second_record(first, second, selector)
356
+ rec = self.class.new(
357
+ self.class::FETCH2K => second.slice(selector),
358
+ self.class::FETCH1K => first
359
+ ).normalize
360
+
361
+ if rec.class == self.class
362
+ RecordSelection.new(record: rec, selector: selector)
363
+ else
364
+ rec.fetch(selector)
365
+ end
366
+ end
367
+
368
+ def fetch(selector)
369
+ first = public_send(self.class::FETCH1K)
370
+ second = public_send(self.class::FETCH2K)
371
+ if first.is_a?(Record)
372
+ first.fetch(selector) { second.fetch(selector) }
373
+ elsif second.is_a?(Record)
374
+ fetch_second_record(first, second, selector)
375
+ else
376
+ super
377
+ end
378
+ end
379
+ end
380
+
350
381
  class Or < Operator; end
351
382
  class And < Operator; end
352
383
  class Equal < Operator; end
@@ -355,17 +386,27 @@ module Dhall
355
386
  class Times < Operator; end
356
387
  class TextConcatenate < Operator; end
357
388
  class ListConcatenate < Operator; end
358
- class RecursiveRecordMerge < Operator; end
359
- class RightBiasedRecordMerge < Operator; end
389
+ class RecursiveRecordMerge < Operator
390
+ FETCH1K = :lhs
391
+ FETCH2K = :rhs
392
+ include FetchFromMerge
393
+ end
394
+ class RightBiasedRecordMerge < Operator
395
+ FETCH1K = :rhs
396
+ FETCH2K = :lhs
397
+ include FetchFromMerge
398
+ end
360
399
  class RecursiveRecordTypeMerge < Operator; end
361
400
  class ImportFallback < Operator; end
401
+ class Equivalent < Operator; end
362
402
 
363
403
  OPERATORS = [
364
404
  Or, And, Equal, NotEqual,
365
405
  Plus, Times,
366
406
  TextConcatenate, ListConcatenate,
367
407
  RecursiveRecordMerge, RightBiasedRecordMerge, RecursiveRecordTypeMerge,
368
- ImportFallback
408
+ ImportFallback,
409
+ Equivalent
369
410
  ].freeze
370
411
  end
371
412
 
@@ -870,6 +911,10 @@ module Dhall
870
911
  end
871
912
  end
872
913
 
914
+ def fetch(selector)
915
+ record.fetch(selector)
916
+ end
917
+
873
918
  def as_json
874
919
  [10, record.as_json, *selectors]
875
920
  end
@@ -881,6 +926,10 @@ module Dhall
881
926
  selector Expression
882
927
  end)
883
928
 
929
+ def fetch(selector)
930
+ record.fetch(selector)
931
+ end
932
+
884
933
  def as_json
885
934
  [10, record.as_json, [selector.as_json]]
886
935
  end
@@ -1299,7 +1348,8 @@ module Dhall
1299
1348
  expr = expr.normalize
1300
1349
  return expr if expr.cache_key == to_s
1301
1350
 
1302
- raise FailureException, "#{expr} does not match #{self}"
1351
+ raise FailureException, "#{expr} hash #{expr.cache_key}" \
1352
+ " does not match #{self}"
1303
1353
  end
1304
1354
 
1305
1355
  def as_json
@@ -1317,7 +1367,7 @@ module Dhall
1317
1367
  def hexdigest; end
1318
1368
 
1319
1369
  def check(expr)
1320
- expr
1370
+ expr.normalize
1321
1371
  end
1322
1372
 
1323
1373
  def as_json
@@ -1402,7 +1452,7 @@ module Dhall
1402
1452
  end
1403
1453
 
1404
1454
  def path
1405
- path = uri.path.split(/\//, -1).map(&::URI.method(:unescape))
1455
+ path = uri.path.split(/\//, -1)
1406
1456
  path = path[1..-1] if path.length > 1 && path.first.empty?
1407
1457
  path
1408
1458
  end
@@ -1690,8 +1740,10 @@ module Dhall
1690
1740
  path.chain_onto(relative_to).canonical
1691
1741
  end
1692
1742
 
1693
- def parse_and_check(raw, deadline: Util::NoDeadline.new)
1694
- integrity_check.check(import_type.call(raw, deadline: deadline))
1743
+ def parse_resolve_check(raw, deadline: Util::NoDeadline.new, **kwargs)
1744
+ import_type.call(raw, deadline: deadline).resolve(**kwargs).then do |e|
1745
+ integrity_check.check(TypeChecker.annotate(e))
1746
+ end
1695
1747
  end
1696
1748
 
1697
1749
  def cache_key(relative_to)
@@ -1738,10 +1790,10 @@ module Dhall
1738
1790
 
1739
1791
  def flatten
1740
1792
  flattened = body.is_a?(LetIn) ? body.flatten : body
1741
- if flattened.is_a?(LetIn) || flattened.is_a?(LetBlock)
1742
- LetBlock.for(lets: [let] + flattened.lets, body: flattened.body)
1793
+ if flattened.is_a?(LetBlock)
1794
+ LetBlock.new(lets: lets + flattened.lets, body: flattened.body)
1743
1795
  else
1744
- self
1796
+ LetBlock.new(lets: lets, body: body)
1745
1797
  end
1746
1798
  end
1747
1799
 
@@ -1764,28 +1816,16 @@ module Dhall
1764
1816
  end
1765
1817
 
1766
1818
  def as_json
1767
- [25, *let.as_json, body.as_json]
1819
+ flatten.as_json
1768
1820
  end
1769
1821
  end
1770
1822
 
1771
- class LetBlock < Expression
1823
+ class LetBlock
1772
1824
  include(ValueSemantics.for_attributes do
1773
- lets Util::ArrayOf.new(Let, min: 2)
1825
+ lets Util::ArrayOf.new(Let)
1774
1826
  body Expression
1775
1827
  end)
1776
1828
 
1777
- def self.for(lets:, body:)
1778
- if lets.length == 1
1779
- LetIn.new(let: lets.first, body: body)
1780
- else
1781
- new(lets: lets, body: body)
1782
- end
1783
- end
1784
-
1785
- def flatten
1786
- unflatten.flatten
1787
- end
1788
-
1789
1829
  def unflatten
1790
1830
  lets.reverse.reduce(body) do |inside, let|
1791
1831
  letin = LetIn.new(let: let, body: inside)
@@ -1793,10 +1833,6 @@ module Dhall
1793
1833
  end
1794
1834
  end
1795
1835
 
1796
- def desugar
1797
- unflatten(&:desugar)
1798
- end
1799
-
1800
1836
  def as_json
1801
1837
  [25, *lets.flat_map(&:as_json), body.as_json]
1802
1838
  end
@@ -1812,4 +1848,14 @@ module Dhall
1812
1848
  [26, value.as_json, type.as_json]
1813
1849
  end
1814
1850
  end
1851
+
1852
+ class Assertion < Expression
1853
+ include(ValueSemantics.for_attributes do
1854
+ type Expression
1855
+ end)
1856
+
1857
+ def as_json
1858
+ [19, type.as_json]
1859
+ end
1860
+ end
1815
1861
  end
@@ -213,6 +213,12 @@ module Dhall
213
213
  end
214
214
  end
215
215
 
216
+ class Assertion
217
+ def self.decode(type)
218
+ new(type: Dhall.decode(type))
219
+ end
220
+ end
221
+
216
222
  class Import
217
223
  class IntegrityCheck
218
224
  def self.decode(integrity_check)
@@ -230,7 +236,7 @@ module Dhall
230
236
  def self.decode(headers, authority, *path, query)
231
237
  uri = ::URI.scheme_list[name.split(/::/).last.upcase].build(
232
238
  Parser.parse(authority, root: :authority).value.merge(
233
- path: Util.path_components_to_uri(*path).path
239
+ path: "/#{path.join("/")}"
234
240
  )
235
241
  )
236
242
  uri.instance_variable_set(:@query, query)
@@ -268,18 +274,18 @@ module Dhall
268
274
  end
269
275
  end
270
276
 
271
- class LetBlock
277
+ class LetIn
272
278
  def self.decode(*parts)
273
279
  body = Dhall.decode(parts.pop)
274
- lets = parts.each_slice(3).map do |(var, type, assign)|
280
+ parts.each_slice(3).map { |(var, type, assign)|
275
281
  Let.new(
276
282
  var: var,
277
283
  assign: Dhall.decode(assign),
278
284
  type: type.nil? ? nil : Dhall.decode(type)
279
285
  )
286
+ }.reverse.reduce(body) do |inside, let|
287
+ LetIn.new(let: let, body: inside)
280
288
  end
281
-
282
- self.for(lets: lets, body: body)
283
289
  end
284
290
  end
285
291
 
@@ -335,13 +341,13 @@ module Dhall
335
341
  Integer,
336
342
  nil,
337
343
  TextLiteral,
338
- nil,
344
+ Assertion,
339
345
  nil,
340
346
  nil,
341
347
  nil,
342
348
  nil,
343
349
  Import,
344
- LetBlock,
350
+ LetIn,
345
351
  TypeAnnotation,
346
352
  ToMap,
347
353
  EmptyList
@@ -98,6 +98,26 @@ module Dhall
98
98
  end
99
99
  end
100
100
 
101
+ class Natural_subtract < BuiltinFunction
102
+ protected
103
+
104
+ def uncurried_call(x, y)
105
+ return y if zero?(x) || zero?(y)
106
+
107
+ return Dhall::Natural.new(value: 0) if x == y
108
+
109
+ unless x.is_a?(Dhall::Natural) && y.is_a?(Dhall::Natural)
110
+ return unfill(x, y)
111
+ end
112
+
113
+ Dhall::Natural.new(value: [y.to_i - x.to_i, 0].max)
114
+ end
115
+
116
+ def zero?(x)
117
+ Natural_isZero.new.call(x) === true
118
+ end
119
+ end
120
+
101
121
  class Natural_even < BuiltinFunction
102
122
  protected
103
123
 
@@ -1,26 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dhall/builtins"
4
- require "dhall/visitor"
5
4
  require "dhall/util"
6
5
 
7
6
  module Dhall
8
- module ExpressionVisitor
7
+ class ExpressionVisitor
9
8
  ExpressionHash = Util::HashOf.new(
10
9
  ValueSemantics::Anything,
11
10
  ValueSemantics::Either.new([Expression, nil])
12
11
  )
13
12
 
14
- def self.new(&block)
15
- Visitor.new(
16
- Expression => block,
17
- Util::ArrayOf.new(Expression) => lambda do |x|
18
- x.map(&block)
19
- end,
20
- ExpressionHash => lambda do |x|
21
- Hash[x.map { |k, v| [k, v.nil? ? v : block[v]] }.sort]
22
- end
23
- )
13
+ ExpressionArray = Util::ArrayOf.new(Expression)
14
+
15
+ def initialize(&block)
16
+ @block = block
17
+ end
18
+
19
+ def visit(expr)
20
+ expr.to_h.each_with_object({}) do |(attr, value), h|
21
+ result = one_visit(value)
22
+ h[attr] = result if result
23
+ end
24
+ end
25
+
26
+ def one_visit(value)
27
+ case value
28
+ when Expression
29
+ @block[value]
30
+ when ExpressionArray
31
+ value.map(&@block)
32
+ when ExpressionHash
33
+ Hash[value.map { |k, v| [k, v.nil? ? v : @block[v]] }.sort]
34
+ end
24
35
  end
25
36
  end
26
37
 
@@ -138,6 +149,8 @@ module Dhall
138
149
  def shift(amount, name, min_index)
139
150
  return self if self.name != name || min_index > index
140
151
 
152
+ raise TypeError, "free variable" if (index + amount).negative?
153
+
141
154
  with(index: index + amount)
142
155
  end
143
156
 
@@ -232,7 +245,10 @@ module Dhall
232
245
 
233
246
  class RightBiasedRecordMerge
234
247
  def normalize
235
- lhs.normalize.merge(rhs.normalize)
248
+ n_lhs = lhs.normalize
249
+ n_rhs = rhs.normalize
250
+ return n_lhs if n_lhs == n_rhs
251
+ n_lhs.merge(n_rhs)
236
252
  end
237
253
  end
238
254
 
@@ -441,20 +457,6 @@ module Dhall
441
457
  end
442
458
  end
443
459
 
444
- class LetBlock
445
- def normalize
446
- desugar.normalize
447
- end
448
-
449
- def shift(amount, name, min_index)
450
- unflatten.shift(amount, name, min_index)
451
- end
452
-
453
- def substitute(svar, with_expr)
454
- unflatten.substitute(svar, with_expr)
455
- end
456
- end
457
-
458
460
  class TypeAnnotation
459
461
  def normalize
460
462
  value.normalize
@@ -85,7 +85,7 @@ rule double_quote_literal
85
85
  (/"/i ((double_quote_chunk)*) /"/i) <Dhall::Parser::DoubleQuoteLiteral>
86
86
  end
87
87
  rule single_quote_continue
88
- (((interpolation) (single_quote_continue)) | ((escaped_quote_pair) (single_quote_continue)) | ((escaped_interpolation) (single_quote_continue)) | ((single_quote_char) (single_quote_continue)) | (`''`)) <Dhall::Parser::SingleQuoteContinue>
88
+ (single_quote_char+ single_quote_continue | interpolation single_quote_continue | escaped_quote_pair single_quote_continue | escaped_interpolation single_quote_continue | "''") <Dhall::Parser::SingleQuoteContinue>
89
89
  end
90
90
  rule escaped_quote_pair
91
91
  (`'''`) <Dhall::Parser::EscapedQuotePair>
@@ -94,7 +94,7 @@ rule escaped_interpolation
94
94
  (/(?:''(?:\u{24}))(?:\u{7b})/i) <Dhall::Parser::EscapedInterpolation>
95
95
  end
96
96
  rule single_quote_char
97
- (/[\u{20}-@\u{5b}-\u{7f}]/i | (valid_non_ascii) | (tab) | (end_of_line))
97
+ !("${" | "''") (/[\u{20}-@\u{5b}-\u{7f}]/i | (valid_non_ascii) | (tab) | (end_of_line))
98
98
  end
99
99
  rule single_quote_literal
100
100
  (`''` (end_of_line) (single_quote_continue)) <Dhall::Parser::SingleQuoteLiteral>
@@ -144,11 +144,14 @@ end
144
144
  rule tomap
145
145
  ("toMap")
146
146
  end
147
+ rule assert
148
+ ("assert")
149
+ end
147
150
  rule keyword
148
151
  ((if) | (then) | (else) | (let) | (in) | (using) | (missing) | (as) | (infinity) | (nan) | (merge) | (some) | (tomap))
149
152
  end
150
153
  rule builtin
151
- ((natural_fold) | (natural_build) | (natural_iszero) | (natural_even) | (natural_odd) | (natural_tointeger) | (natural_show) | (integer_todouble) | (integer_show) | (double_show) | (list_build) | (list_fold) | (list_length) | (list_head) | (list_last) | (list_indexed) | (list_reverse) | (optional_fold) | (optional_build) | (text_show) | (bool) | (true) | (false) | (optional) | (none) | (natural) | (integer) | (double) | (text) | (list) | (type) | (kind) | (sort)) <Dhall::Parser::Builtin>
154
+ ((natural_fold) | (natural_build) | (natural_iszero) | (natural_even) | (natural_odd) | (natural_tointeger) | (natural_show) | (integer_todouble) | (integer_show) | (natural_subtract) | (double_show) | (list_build) | (list_fold) | (list_length) | (list_head) | (list_last) | (list_indexed) | (list_reverse) | (optional_fold) | (optional_build) | (text_show) | (bool) | (true) | (false) | (optional) | (none) | (natural) | (integer) | (double) | (text) | (list) | (type) | (kind) | (sort)) <Dhall::Parser::Builtin>
152
155
  end
153
156
  rule optional
154
157
  ("Optional")
@@ -213,6 +216,9 @@ end
213
216
  rule natural_show
214
217
  ("Natural" /\//i "s" "h" "o" "w")
215
218
  end
219
+ rule natural_subtract
220
+ ("Natural" /\//i "s" "u" "b" "t" "r" "a" "c" "t")
221
+ end
216
222
  rule integer_todouble
217
223
  ("Integer" /\//i "t" "o" "D" "o" "u" "b" "l" "e")
218
224
  end
@@ -258,6 +264,9 @@ end
258
264
  rule combine_types
259
265
  (/\u{2a53}/i | (/(?:(?:(?:\/)(?:\/))(?:\u{5c}))(?:\u{5c})/i))
260
266
  end
267
+ rule equivalent
268
+ (/\u{2261}/i | (/(?:(?:=)(?:=))(?:=)/i))
269
+ end
261
270
  rule prefer
262
271
  (/\u{2afd}/i | (/(?:\/)(?:\/)/i))
263
272
  end
@@ -424,7 +433,7 @@ rule import
424
433
  ((import_hashed) (((whsp) (as) (whsp1) ((text) | (location)))?)) <Dhall::Parser::Import>
425
434
  end
426
435
  rule expression
427
- (((lambda) (whsp) /\u{28}/i (whsp) (nonreserved_label) (whsp) `:` (whsp1) (expression) (whsp) /\u{29}/i (whsp) (arrow) (whsp) (expression)) | ((if) (whsp1) (expression) (whsp) (then) (whsp1) (expression) (whsp) (else) (whsp1) (expression)) | (((let_binding)+) (in) (whsp1) (expression)) | ((forall) (whsp) /\u{28}/i (whsp) (nonreserved_label) (whsp) `:` (whsp1) (expression) (whsp) /\u{29}/i (whsp) (arrow) (whsp) (expression)) | ((operator_expression) (whsp) (arrow) (whsp) (expression)) | ((merge) (whsp1) (import_expression) (whsp1) (import_expression) (whsp) `:` (whsp1) (application_expression)) | (/\u{5b}/i (whsp) /\u{5d}/i (whsp) `:` (whsp1) (application_expression)) | ((tomap) (whsp1) (import_expression) (whsp) `:` (whsp1) (application_expression)) | (annotated_expression)) <Dhall::Parser::Expression>
436
+ (((lambda) (whsp) /\u{28}/i (whsp) (nonreserved_label) (whsp) `:` (whsp1) (expression) (whsp) /\u{29}/i (whsp) (arrow) (whsp) (expression)) | ((if) (whsp1) (expression) (whsp) (then) (whsp1) (expression) (whsp) (else) (whsp1) (expression)) | (((let_binding)+) (in) (whsp1) (expression)) | ((forall) (whsp) /\u{28}/i (whsp) (nonreserved_label) (whsp) `:` (whsp1) (expression) (whsp) /\u{29}/i (whsp) (arrow) (whsp) (expression)) | ((operator_expression) (whsp) (arrow) (whsp) (expression)) | ((merge) (whsp1) (import_expression) (whsp1) (import_expression) (whsp) `:` (whsp1) (application_expression)) | (empty_list_literal) | ((tomap) (whsp1) (import_expression) (whsp) `:` (whsp1) (application_expression)) | ((assert) (whsp) `:` (whsp1) (expression)) | (annotated_expression)) <Dhall::Parser::Expression>
428
437
  end
429
438
  rule annotated_expression
430
439
  ((operator_expression) (((whsp) `:` (whsp1) (expression))?)) <Dhall::Parser::AnnotatedExpression>
@@ -432,6 +441,9 @@ end
432
441
  rule let_binding
433
442
  ((let) (whsp1) (nonreserved_label) (whsp) ((`:` (whsp1) (expression) (whsp))?) /=/i (whsp) (expression) (whsp)) <Dhall::Parser::LetBinding>
434
443
  end
444
+ rule empty_list_literal
445
+ (/\u{5b}/i (whsp) /\u{5d}/i (whsp) `:` (whsp1) (application_expression))
446
+ end
435
447
  rule operator_expression
436
448
  (import_alt_expression)
437
449
  end
@@ -469,7 +481,10 @@ rule equal_expression
469
481
  ((not_equal_expression) (((whsp) /(?:=)(?:=)/i (whsp) (not_equal_expression))*)) <Dhall::Parser::EqualExpression>
470
482
  end
471
483
  rule not_equal_expression
472
- ((application_expression) (((whsp) /(?:!)(?:=)/i (whsp) (application_expression))*)) <Dhall::Parser::NotEqualExpression>
484
+ ((equivalent_expression) (((whsp) /(?:!)(?:=)/i (whsp) (equivalent_expression))*)) <Dhall::Parser::NotEqualExpression>
485
+ end
486
+ rule equivalent_expression
487
+ ((application_expression) (((whsp) (equivalent) (whsp) (application_expression))*)) <Dhall::Parser::EquivalentExpression>
473
488
  end
474
489
  rule application_expression
475
490
  ((first_application_expression) (((whsp1) (import_expression))*)) <Dhall::Parser::ApplicationExpression>
@@ -493,7 +508,7 @@ rule type_selector
493
508
  (/\u{28}/i (whsp) (expression) (whsp) /\u{29}/i)
494
509
  end
495
510
  rule primitive_expression
496
- ((double_literal) | (natural_literal) | (integer_literal) | (text_literal) | (/\u{7b}/i (whsp) (record_type_or_literal) (whsp) /\u{7d}/i) | (/</i (whsp) (union_type_or_literal) (whsp) />/i) | (non_empty_list_literal) | (identifier) | (/\u{28}/i (complete_expression) /\u{29}/i)) <Dhall::Parser::PrimitiveExpression>
511
+ ((double_literal) | (natural_literal) | (integer_literal) | (text_literal) | (/\u{7b}/i (whsp) (record_type_or_literal) (whsp) /\u{7d}/i) | (/</i (whsp) (union_type) (whsp) />/i) | (non_empty_list_literal) | (identifier) | (/\u{28}/i (complete_expression) /\u{29}/i)) <Dhall::Parser::PrimitiveExpression>
497
512
  end
498
513
  rule record_type_or_literal
499
514
  ((empty_record_literal) | (non_empty_record_type_or_literal) | (empty_record_type))
@@ -519,24 +534,18 @@ end
519
534
  rule record_literal_entry
520
535
  ((any_label) (whsp) /=/i (whsp) (expression)) <Dhall::Parser::RecordLiteralEntry>
521
536
  end
522
- rule union_type_or_literal
523
- ((non_empty_union_type_or_literal) | (empty_union_type))
537
+ rule union_type
538
+ ((non_empty_union_type) | (empty_union_type))
524
539
  end
525
540
  rule empty_union_type
526
541
  ("") <Dhall::Parser::EmptyUnionType>
527
542
  end
528
- rule non_empty_union_type_or_literal
529
- ((any_label) (((whsp) ((union_literal_variant_value) | (union_type_or_literal_variant_type)))?)) <Dhall::Parser::NonEmptyUnionTypeOrLiteral>
530
- end
531
- rule union_literal_variant_value
532
- (/=/i (whsp) (expression) (((whsp) /\u{7c}/i (whsp) (union_type_entry))*)) <Dhall::Parser::UnionLiteralVariantValue>
543
+ rule non_empty_union_type
544
+ ((union_type_entry) (((whsp) /\u{7c}/i (whsp) (union_type_entry))*)) <Dhall::Parser::NonEmptyUnionType>
533
545
  end
534
546
  rule union_type_entry
535
547
  ((any_label) (((whsp) `:` (whsp1) (expression))?)) <Dhall::Parser::UnionTypeEntry>
536
548
  end
537
- rule union_type_or_literal_variant_type
538
- (((`:` (whsp1) (expression))?) (((whsp) /\u{7c}/i (whsp) (non_empty_union_type_or_literal))?)) <Dhall::Parser::UnionTypeOrLiteralVariantType>
539
- end
540
549
  rule non_empty_list_literal
541
550
  (/\u{5b}/i (whsp) (expression) (whsp) ((/,/i (whsp) (expression) (whsp))*) /\u{5d}/i) <Dhall::Parser::NonEmptyListLiteral>
542
551
  end
@@ -24,17 +24,18 @@ module Dhall
24
24
  return list if string =~ /\A\[\s*\]/
25
25
 
26
26
  key =
27
- [:let_binding, :lambda, :forall, :arrow, :if, :merge, :tomap]
27
+ [:let_binding, :lambda, :forall, :arrow, :if, :merge, :tomap, :assert]
28
28
  .find { |k| captures.key?(k) }
29
29
 
30
30
  key ? public_send(key) : super
31
31
  end
32
32
 
33
33
  def let_binding
34
- LetBlock.for(
35
- lets: captures(:let_binding).map(&:value),
36
- body: capture(:expression).value
37
- )
34
+ captures(:let_binding).reverse.reduce(
35
+ capture(:expression).value
36
+ ) do |inside, let|
37
+ LetIn.new(let: let.value, body: inside)
38
+ end
38
39
  end
39
40
 
40
41
  def lambda
@@ -86,6 +87,10 @@ module Dhall
86
87
  type: capture(:application_expression).value
87
88
  )
88
89
  end
90
+
91
+ def assert
92
+ Assertion.new(type: capture(:expression).value)
93
+ end
89
94
  end
90
95
 
91
96
  OPERATORS = {
@@ -100,7 +105,8 @@ module Dhall
100
105
  combine_types_expression: :RecursiveRecordTypeMerge,
101
106
  times_expression: :Times,
102
107
  equal_expression: :Equal,
103
- not_equal_expression: :NotEqual
108
+ not_equal_expression: :NotEqual,
109
+ equivalent_expression: :Equivalent
104
110
  }.freeze
105
111
 
106
112
  OPERATORS.to_a.zip(
@@ -169,7 +175,7 @@ module Dhall
169
175
  elsif captures.key?(:labels)
170
176
  captures(:any_label).map(&:value)
171
177
  else
172
- string
178
+ super
173
179
  end
174
180
  end
175
181
  end
@@ -314,7 +320,9 @@ module Dhall
314
320
 
315
321
  module SingleQuoteLiteral
316
322
  def value
317
- chunks = capture(:single_quote_continue).value
323
+ chunks = capture(:single_quote_continue).value.flat_map do |chunk|
324
+ chunk.is_a?(String) ? chunk.gsub(/\r\n/, "\n").chars : chunk
325
+ end
318
326
  indent = Util.indent_size(chunks.join)
319
327
 
320
328
  TextLiteral.for(
@@ -384,7 +392,7 @@ module Dhall
384
392
  key = [
385
393
  :complete_expression,
386
394
  :record_type_or_literal,
387
- :union_type_or_literal
395
+ :union_type
388
396
  ].find { |k| captures.key?(k) }
389
397
  key ? capture(key).value : super
390
398
  end
@@ -396,31 +404,6 @@ module Dhall
396
404
  end
397
405
  end
398
406
 
399
- module UnionTypeOrLiteralVariantType
400
- def value(label)
401
- rest = capture(:non_empty_union_type_or_literal)&.value
402
- type = UnionType.new(
403
- alternatives: { label => capture(:expression)&.value }
404
- )
405
- if rest.is_a?(Union)
406
- rest.with(alternatives: type.merge(rest.alternatives))
407
- else
408
- rest ? type.merge(rest) : type
409
- end
410
- end
411
- end
412
-
413
- module UnionLiteralVariantValue
414
- def value(label)
415
- Union.new(
416
- tag: label,
417
- value: capture(:expression).value,
418
- alternatives: captures(:union_type_entry).map(&:value)
419
- .reduce(UnionType.new(alternatives: {}), &:merge)
420
- )
421
- end
422
- end
423
-
424
407
  module UnionTypeEntry
425
408
  def value
426
409
  UnionType.new(
@@ -431,19 +414,9 @@ module Dhall
431
414
  end
432
415
  end
433
416
 
434
- module NonEmptyUnionTypeOrLiteral
417
+ module NonEmptyUnionType
435
418
  def value
436
- key = [
437
- :union_literal_variant_value,
438
- :union_type_or_literal_variant_type
439
- ].find { |k| captures.key?(k) }
440
-
441
- if key
442
- capture(key).value(capture(:any_label).value)
443
- else
444
- no_alts = UnionType.new(alternatives: {})
445
- Union.from(no_alts, capture(:any_label).value, nil)
446
- end
419
+ captures(:union_type_entry).map(&:value).reduce(&:merge)
447
420
  end
448
421
  end
449
422
 
@@ -16,13 +16,13 @@ module Dhall
16
16
  module Resolvers
17
17
  ReadPathSources = lambda do |sources|
18
18
  sources.map do |source|
19
- Promise.resolve(nil).then { source.pathname.binread }
19
+ Util::LazyPromise.new { source.pathname.binread }
20
20
  end
21
21
  end
22
22
 
23
23
  ReadEnvironmentSources = lambda do |sources|
24
24
  sources.map do |source|
25
- Promise.resolve(nil).then do
25
+ Util::LazyPromise.new do
26
26
  ENV.fetch(source.var) do
27
27
  raise ImportFailedException, "No #{source}"
28
28
  end
@@ -53,7 +53,7 @@ module Dhall
53
53
 
54
54
  ReadHttpSources = lambda do |sources, parent_origin|
55
55
  sources.map do |source|
56
- Promise.resolve(nil).then do
56
+ Util::LazyPromise.new do
57
57
  PreflightCORS.call(source, parent_origin)
58
58
  timeout = source.deadline.timeout
59
59
  uri = source.uri
@@ -449,7 +449,9 @@ module Dhall
449
449
  def resolve_raw(resolver:, relative_to:)
450
450
  real_path = @expr.real_path(relative_to)
451
451
  real_path.resolve(resolver).then do |result|
452
- @expr.parse_and_check(result, deadline: resolver.deadline).resolve(
452
+ @expr.parse_resolve_check(
453
+ result,
454
+ deadline: resolver.deadline,
453
455
  resolver: resolver.child(real_path),
454
456
  relative_to: real_path
455
457
  )
@@ -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
 
@@ -237,6 +239,31 @@ module Dhall
237
239
  end
238
240
  end
239
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
+
240
267
  class OperatorListConcatenate
241
268
  TypeChecker.register self, Dhall::Operator::ListConcatenate
242
269
 
@@ -313,10 +340,6 @@ module Dhall
313
340
  "RecursiveRecordMerge got",
314
341
  context: context
315
342
 
316
- TypeChecker.assert_types_match annotated_lhs.type, annotated_rhs.type,
317
- "RecursiveRecordMerge got mixed kinds",
318
- context: context
319
-
320
343
  [annotated_lhs, annotated_rhs]
321
344
  end
322
345
 
@@ -340,12 +363,6 @@ module Dhall
340
363
  end
341
364
 
342
365
  def annotate(context)
343
- kind = TypeChecker.assert_types_match(
344
- @expr.lhs, @expr.rhs,
345
- "RecursiveRecordTypeMerge mixed kinds",
346
- context: context
347
- )
348
-
349
366
  type = @expr.lhs.deep_merge_type(@expr.rhs)
350
367
 
351
368
  TypeChecker.assert type, Dhall::RecordType,
@@ -354,7 +371,13 @@ module Dhall
354
371
  # Annotate to sanity check
355
372
  TypeChecker.for(type).annotate(context)
356
373
 
357
- 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]
358
381
  end
359
382
  end
360
383
 
@@ -478,13 +501,20 @@ module Dhall
478
501
 
479
502
  class AnonymousType
480
503
  TypeChecker.register self, Dhall::RecordType
481
- TypeChecker.register self, Dhall::UnionType
482
504
 
483
505
  def initialize(type)
484
506
  @type = type
485
507
  end
486
508
 
487
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)
488
518
  kinds = @type.record.values.compact.map do |mtype|
489
519
  TypeChecker.for(mtype).annotate(context).type
490
520
  end
@@ -492,6 +522,16 @@ module Dhall
492
522
  TypeChecker.assert (kinds - KINDS), [],
493
523
  "AnonymousType field kind not one of #{KINDS}"
494
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
+
495
535
  TypeChecker.assert kinds, Util::ArrayAllTheSame,
496
536
  "AnonymousType field kinds not all the same"
497
537
 
@@ -749,7 +789,7 @@ module Dhall
749
789
  end
750
790
 
751
791
  def keys
752
- @type.record.keys
792
+ Set.new(@type.record.keys)
753
793
  end
754
794
 
755
795
  def fetch_input_type(k)
@@ -800,8 +840,8 @@ module Dhall
800
840
  end
801
841
 
802
842
  def assert_union_and_handlers_match
803
- extras = @handlers.keys - @union.type.alternatives.keys
804
- TypeChecker.assert extras, [],
843
+ extras = @handlers.keys ^ @union.type.alternatives.keys
844
+ TypeChecker.assert extras.to_a, [],
805
845
  "Merge handlers unknown alternatives: #{extras}"
806
846
 
807
847
  @union.type.alternatives.each do |k, atype|
@@ -842,8 +882,6 @@ module Dhall
842
882
  raise TypeError, "FunctionType part of this is a term"
843
883
  end
844
884
 
845
- raise TypeError, "Dependent types are not allowed" if outkind > inkind
846
-
847
885
  if outkind.zero?
848
886
  Term.new
849
887
  else
@@ -931,8 +969,6 @@ module Dhall
931
969
  end
932
970
  end
933
971
 
934
- TypeChecker.register ->(blk) { LetIn.for(blk.unflatten) }, Dhall::LetBlock
935
-
936
972
  class LetIn
937
973
  TypeChecker.register self, Dhall::LetIn
938
974
 
@@ -998,6 +1034,30 @@ module Dhall
998
1034
  end
999
1035
  end
1000
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
+
1001
1061
  BUILTIN_TYPES = {
1002
1062
  "Bool" => Builtins[:Type],
1003
1063
  "Type" => Builtins[:Kind],
@@ -1060,6 +1120,11 @@ module Dhall
1060
1120
  )
1061
1121
  )
1062
1122
  ),
1123
+ "Natural/subtract" => Dhall::Forall.of_arguments(
1124
+ Builtins[:Natural],
1125
+ Builtins[:Natural],
1126
+ body: Builtins[:Natural]
1127
+ ),
1063
1128
  "Natural/isZero" => Dhall::Forall.of_arguments(
1064
1129
  Builtins[:Natural],
1065
1130
  body: Builtins[:Bool]
@@ -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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dhall
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
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-07-27 00:00:00.000000000 Z
11
+ date: 2019-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
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
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: simplecov
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -181,7 +195,6 @@ files:
181
195
  - lib/dhall/typecheck.rb
182
196
  - lib/dhall/types.rb
183
197
  - lib/dhall/util.rb
184
- - lib/dhall/visitor.rb
185
198
  homepage: https://git.sr.ht/~singpolyma/dhall-ruby
186
199
  licenses:
187
200
  - GPL-3.0
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dhall
4
- class Visitor
5
- def initialize(callbacks)
6
- @callbacks = callbacks
7
- end
8
-
9
- def visit(expr)
10
- expr.to_h.each_with_object({}) do |(attr, value), h|
11
- if (callback = callback_for(value))
12
- h[attr] = callback.call(value)
13
- end
14
- end
15
- end
16
-
17
- protected
18
-
19
- def callback_for(x)
20
- @callbacks.find { |k, _| k === x }&.last
21
- end
22
- end
23
- end