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 +4 -4
- data/dhall.gemspec +1 -0
- data/lib/dhall/ast.rb +76 -30
- data/lib/dhall/binary.rb +13 -7
- data/lib/dhall/builtins.rb +20 -0
- data/lib/dhall/normalize.rb +29 -27
- data/lib/dhall/parser.citrus +25 -16
- data/lib/dhall/parser.rb +19 -46
- data/lib/dhall/resolve.rb +6 -4
- data/lib/dhall/typecheck.rb +85 -20
- data/lib/dhall/util.rb +18 -0
- metadata +16 -3
- data/lib/dhall/visitor.rb +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7132b6745d968ae3d719249d6b996438b99b9a3f
|
4
|
+
data.tar.gz: 33c3de17c1b2dc921024f3fb14aeba7fb89624c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89f23e3937ebe15c2a2b693ef5056802a4edc5ccb529ca37e9c8eb43f611b8f9477b722116c5ac143ec10c346c8e61e03f66b3d677984efb84214fbc9d7a45b4
|
7
|
+
data.tar.gz: 26fcce26e98bc480b6d14adaf482debe2ad99dac6d997af1352f6e5cf89dc8930ea3a2766857b984c023d07140c50b672e0635c33f8505820e325ec5bd5a21cf
|
data/dhall.gemspec
CHANGED
@@ -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
|
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
|
359
|
-
|
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}
|
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)
|
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
|
1694
|
-
|
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?(
|
1742
|
-
LetBlock.
|
1793
|
+
if flattened.is_a?(LetBlock)
|
1794
|
+
LetBlock.new(lets: lets + flattened.lets, body: flattened.body)
|
1743
1795
|
else
|
1744
|
-
|
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
|
-
|
1819
|
+
flatten.as_json
|
1768
1820
|
end
|
1769
1821
|
end
|
1770
1822
|
|
1771
|
-
class LetBlock
|
1823
|
+
class LetBlock
|
1772
1824
|
include(ValueSemantics.for_attributes do
|
1773
|
-
lets Util::ArrayOf.new(Let
|
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:
|
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
|
277
|
+
class LetIn
|
272
278
|
def self.decode(*parts)
|
273
279
|
body = Dhall.decode(parts.pop)
|
274
|
-
|
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
|
-
|
344
|
+
Assertion,
|
339
345
|
nil,
|
340
346
|
nil,
|
341
347
|
nil,
|
342
348
|
nil,
|
343
349
|
Import,
|
344
|
-
|
350
|
+
LetIn,
|
345
351
|
TypeAnnotation,
|
346
352
|
ToMap,
|
347
353
|
EmptyList
|
data/lib/dhall/builtins.rb
CHANGED
@@ -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/normalize.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
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
|
data/lib/dhall/parser.citrus
CHANGED
@@ -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
|
-
(
|
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)) | (
|
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
|
-
((
|
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) (
|
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
|
523
|
-
((
|
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
|
529
|
-
((
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
-
:
|
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
|
417
|
+
module NonEmptyUnionType
|
435
418
|
def value
|
436
|
-
|
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
@@ -16,13 +16,13 @@ module Dhall
|
|
16
16
|
module Resolvers
|
17
17
|
ReadPathSources = lambda do |sources|
|
18
18
|
sources.map do |source|
|
19
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
)
|
data/lib/dhall/typecheck.rb
CHANGED
@@ -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
|
-
|
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
|
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
|
+
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-
|
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
|
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
|