dhall 0.4.0 → 0.5.3.fixed

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 55053ce451e1b675998712636c725380329d1fe6
4
- data.tar.gz: d98038e234871e81f8c0ce3f6d2a8f7c941b8278
2
+ SHA256:
3
+ metadata.gz: 6ef819cfd9041e4eca3854a27df5c1161f3d1d6a852d6356d4997a93a0497747
4
+ data.tar.gz: 44d7fe35ff3da98c0ec16ea074ccb103538918c864e7d870190c234b94edb154
5
5
  SHA512:
6
- metadata.gz: 4735802d9beb7c796d06ba6c887f5776ac24f12342ad754d911cc36593fb730f0c4d861b653b3667ad1590835014ffcf865e1aa4bd5a56f3c4d9b4e49274d808
7
- data.tar.gz: 386cda30b6cd93ea7b6236bab460681554240355e25609c4791cb7d85cf6ff07f3b6a3d6b2a3727c2d6d9d8c2123105b4bcf1a03f1cb0272baa2651b4c0c7159
6
+ metadata.gz: b1282cd55e04396e3e0642f0621c2119a64535ca3b0bfae4be3eb2ff4a0bcda0bafdb8b312841d0357932a1e411122cd50186a6534f63ce87ad6b6376df7bfd9
7
+ data.tar.gz: 7d4287f4f5ee378197ded560dc188fe54147a6221cbc6b3ac0b74e5b03188c11b86f76573dbf1ab791836aa36450316126afea1ed5a29aebba363465960bf674
data/dhall.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "dhall"
5
- spec.version = `git describe --always --dirty`
5
+ spec.version = "0.5.3.fixed"
6
6
  spec.authors = ["Stephen Paul Weber"]
7
7
  spec.email = ["dev@singpolyma.net"]
8
8
  spec.license = "GPL-3.0"
@@ -29,11 +29,12 @@ Gem::Specification.new do |spec|
29
29
  spec.add_dependency "cbor", "~> 0.5.9.3"
30
30
  spec.add_dependency "citrus", "~> 3.0"
31
31
  spec.add_dependency "lazy_object", "~> 0.0.3"
32
- spec.add_dependency "multihashes", "~> 0.1.3"
32
+ spec.add_dependency "multihashes", "~> 0.2.0"
33
33
  spec.add_dependency "promise.rb", "~> 0.7.4"
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
data/lib/dhall/ast.rb CHANGED
@@ -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
@@ -1056,8 +1105,8 @@ module Dhall
1056
1105
  class If < Expression
1057
1106
  include(ValueSemantics.for_attributes do
1058
1107
  predicate Expression
1059
- self.then Expression
1060
- self.else Expression
1108
+ def_attr :then, Expression
1109
+ def_attr :else, Expression
1061
1110
  end)
1062
1111
 
1063
1112
  def as_json
@@ -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
data/lib/dhall/binary.rb CHANGED
@@ -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
 
data/lib/dhall/coder.rb CHANGED
@@ -105,12 +105,11 @@ module Dhall
105
105
 
106
106
  refine List do
107
107
  def to_ruby(&decode)
108
- arr = to_a.map(&decode)
109
108
  unless element_type.is_a?(RecordType) &&
110
109
  element_type.keys == ["mapKey", "mapValue"]
111
- return arr
110
+ return to_a.map(&decode)
112
111
  end
113
- Hash[arr.map { |h| h.values_at("mapKey", "mapValue") }]
112
+ Hash[to_a.map { |r| [r["mapKey"].to_s, decode[r["mapValue"]]] }]
114
113
  end
115
114
  end
116
115
 
@@ -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
data/lib/dhall/parser.rb CHANGED
@@ -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
 
data/lib/dhall/resolve.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "delegate"
3
4
  require "pathname"
4
5
  require "promise.rb"
5
6
  require "set"
@@ -16,13 +17,13 @@ module Dhall
16
17
  module Resolvers
17
18
  ReadPathSources = lambda do |sources|
18
19
  sources.map do |source|
19
- Promise.resolve(nil).then { source.pathname.binread }
20
+ Util::LazyPromise.new { source.pathname.binread }
20
21
  end
21
22
  end
22
23
 
23
24
  ReadEnvironmentSources = lambda do |sources|
24
25
  sources.map do |source|
25
- Promise.resolve(nil).then do
26
+ Util::LazyPromise.new do
26
27
  ENV.fetch(source.var) do
27
28
  raise ImportFailedException, "No #{source}"
28
29
  end
@@ -53,7 +54,7 @@ module Dhall
53
54
 
54
55
  ReadHttpSources = lambda do |sources, parent_origin|
55
56
  sources.map do |source|
56
- Promise.resolve(nil).then do
57
+ Util::LazyPromise.new do
57
58
  PreflightCORS.call(source, parent_origin)
58
59
  timeout = source.deadline.timeout
59
60
  uri = source.uri
@@ -449,7 +450,9 @@ module Dhall
449
450
  def resolve_raw(resolver:, relative_to:)
450
451
  real_path = @expr.real_path(relative_to)
451
452
  real_path.resolve(resolver).then do |result|
452
- @expr.parse_and_check(result, deadline: resolver.deadline).resolve(
453
+ @expr.parse_resolve_check(
454
+ result,
455
+ deadline: resolver.deadline,
453
456
  resolver: resolver.child(real_path),
454
457
  relative_to: real_path
455
458
  )
@@ -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]
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
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.3.fixed
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: 2021-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base32
@@ -72,14 +72,14 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.1.3
75
+ version: 0.2.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.1.3
82
+ version: 0.2.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: promise.rb
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -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
@@ -197,12 +210,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
197
210
  version: '0'
198
211
  required_rubygems_version: !ruby/object:Gem::Requirement
199
212
  requirements:
200
- - - ">="
213
+ - - ">"
201
214
  - !ruby/object:Gem::Version
202
- version: '0'
215
+ version: 1.3.1
203
216
  requirements: []
204
- rubyforge_project:
205
- rubygems_version: 2.5.2.1
217
+ rubygems_version: 3.2.5
206
218
  signing_key:
207
219
  specification_version: 4
208
220
  summary: The non-repetitive alternative to YAML, in Ruby
data/lib/dhall/visitor.rb DELETED
@@ -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