dhall 0.1.0 → 0.5.1
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 +5 -5
- data/README.md +31 -4
- data/bin/dhall-compile +111 -0
- data/bin/json-to-dhall +1 -1
- data/bin/yaml-to-dhall +1 -1
- data/dhall.gemspec +5 -1
- data/lib/dhall.rb +25 -11
- data/lib/dhall/as_dhall.rb +132 -33
- data/lib/dhall/ast.rb +512 -210
- data/lib/dhall/binary.rb +102 -24
- data/lib/dhall/builtins.rb +227 -247
- data/lib/dhall/coder.rb +199 -0
- data/lib/dhall/normalize.rb +93 -48
- data/lib/dhall/parser.citrus +177 -83
- data/lib/dhall/parser.rb +199 -118
- data/lib/dhall/resolve.rb +200 -48
- data/lib/dhall/typecheck.rb +292 -129
- data/lib/dhall/types.rb +19 -0
- data/lib/dhall/util.rb +142 -38
- metadata +63 -4
- data/lib/dhall/visitor.rb +0 -23
data/lib/dhall/parser.rb
CHANGED
@@ -21,23 +21,21 @@ module Dhall
|
|
21
21
|
|
22
22
|
module Expression
|
23
23
|
def value
|
24
|
-
|
25
|
-
[:let_binding, :lambda, :forall, :arrow, :if, :merge]
|
26
|
-
.find { |k| captures.key?(k) }
|
27
|
-
|
28
|
-
return public_send(key) if key
|
24
|
+
return list if string =~ /\A\[\s*\]/
|
29
25
|
|
30
26
|
key =
|
31
|
-
[:
|
27
|
+
[:let_binding, :lambda, :forall, :arrow, :if, :merge, :tomap, :assert]
|
32
28
|
.find { |k| captures.key?(k) }
|
33
|
-
|
29
|
+
|
30
|
+
key ? public_send(key) : super
|
34
31
|
end
|
35
32
|
|
36
33
|
def let_binding
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
captures(:let_binding).reverse.reduce(
|
35
|
+
capture(:expression).value
|
36
|
+
) do |inside, let|
|
37
|
+
LetIn.new(let: let.value, body: inside)
|
38
|
+
end
|
41
39
|
end
|
42
40
|
|
43
41
|
def lambda
|
@@ -78,6 +76,21 @@ module Dhall
|
|
78
76
|
type: capture(:application_expression)&.value
|
79
77
|
)
|
80
78
|
end
|
79
|
+
|
80
|
+
def list
|
81
|
+
EmptyList.new(type: capture(:application_expression).value)
|
82
|
+
end
|
83
|
+
|
84
|
+
def tomap
|
85
|
+
ToMap.new(
|
86
|
+
record: capture(:import_expression).value,
|
87
|
+
type: capture(:application_expression).value
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert
|
92
|
+
Assertion.new(type: capture(:expression).value)
|
93
|
+
end
|
81
94
|
end
|
82
95
|
|
83
96
|
OPERATORS = {
|
@@ -92,7 +105,8 @@ module Dhall
|
|
92
105
|
combine_types_expression: :RecursiveRecordTypeMerge,
|
93
106
|
times_expression: :Times,
|
94
107
|
equal_expression: :Equal,
|
95
|
-
not_equal_expression: :NotEqual
|
108
|
+
not_equal_expression: :NotEqual,
|
109
|
+
equivalent_expression: :Equivalent
|
96
110
|
}.freeze
|
97
111
|
|
98
112
|
OPERATORS.to_a.zip(
|
@@ -109,22 +123,44 @@ module Dhall
|
|
109
123
|
|
110
124
|
module ApplicationExpression
|
111
125
|
def value
|
112
|
-
|
113
|
-
els =
|
126
|
+
first_expr = [capture(:first_application_expression).value]
|
127
|
+
els = first_expr + captures(:import_expression).map(&:value)
|
114
128
|
els.reduce do |f, arg|
|
115
129
|
Application.for(function: f, argument: arg)
|
116
130
|
end
|
117
131
|
end
|
118
132
|
end
|
119
133
|
|
134
|
+
module FirstApplicationExpression
|
135
|
+
def value
|
136
|
+
if captures.key?(:merge)
|
137
|
+
merge
|
138
|
+
elsif captures.key?(:some)
|
139
|
+
Optional.new(value: capture(:import_expression).value)
|
140
|
+
elsif captures.key?(:tomap)
|
141
|
+
ToMap.new(record: capture(:import_expression).value)
|
142
|
+
else
|
143
|
+
super
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def merge
|
148
|
+
Merge.new(
|
149
|
+
record: captures(:import_expression)[0].value,
|
150
|
+
input: captures(:import_expression)[1].value,
|
151
|
+
type: nil
|
152
|
+
)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
120
156
|
module SelectorExpression
|
121
157
|
def value
|
122
158
|
record = capture(:primitive_expression).value
|
123
|
-
|
124
|
-
selectors.reduce(record) do |rec, sels|
|
159
|
+
captures(:selector).map(&:value).reduce(record) do |rec, sels|
|
125
160
|
if sels.is_a?(Array)
|
126
|
-
|
127
|
-
|
161
|
+
RecordProjection.for(rec, sels)
|
162
|
+
elsif sels.is_a?(Dhall::Expression)
|
163
|
+
RecordProjectionByExpression.new(record: rec, selector: sels)
|
128
164
|
else
|
129
165
|
RecordSelection.new(record: rec, selector: sels)
|
130
166
|
end
|
@@ -132,18 +168,36 @@ module Dhall
|
|
132
168
|
end
|
133
169
|
end
|
134
170
|
|
135
|
-
module
|
171
|
+
module Selector
|
136
172
|
def value
|
137
|
-
captures(:
|
173
|
+
if captures.key?(:type_selector)
|
174
|
+
capture(:expression).value
|
175
|
+
elsif captures.key?(:labels)
|
176
|
+
captures(:any_label).map(&:value)
|
177
|
+
else
|
178
|
+
super
|
179
|
+
end
|
138
180
|
end
|
139
181
|
end
|
140
182
|
|
141
183
|
module Label
|
184
|
+
module Quoted
|
185
|
+
def quoted?
|
186
|
+
true
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
module Unquoted
|
191
|
+
def quoted?
|
192
|
+
false
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
142
196
|
def value
|
143
197
|
if first.string == "`"
|
144
|
-
matches[1].string
|
198
|
+
matches[1].string.extend(Quoted)
|
145
199
|
else
|
146
|
-
string
|
200
|
+
string.extend(Unquoted)
|
147
201
|
end
|
148
202
|
end
|
149
203
|
end
|
@@ -203,7 +257,7 @@ module Dhall
|
|
203
257
|
.map(&:value)
|
204
258
|
.chunk { |s| s.is_a?(String) }
|
205
259
|
.flat_map do |(strs, group)|
|
206
|
-
strs ? group.
|
260
|
+
strs ? group.join : group
|
207
261
|
end
|
208
262
|
)
|
209
263
|
end
|
@@ -232,24 +286,49 @@ module Dhall
|
|
232
286
|
"t" => "\t"
|
233
287
|
}.freeze
|
234
288
|
|
289
|
+
NON_CHARACTERS = [
|
290
|
+
(0xD800..0xDFFF),
|
291
|
+
(0xFFFE..0xFFFF),
|
292
|
+
(0x1FFFE..0x1FFFF),
|
293
|
+
(0x2FFFE..0x2FFFF),
|
294
|
+
(0x3FFFE..0x3FFFF),
|
295
|
+
(0x4FFFE..0x4FFFF),
|
296
|
+
(0x5FFFE..0x5FFFF),
|
297
|
+
(0x6FFFE..0x6FFFF),
|
298
|
+
(0x7FFFE..0x7FFFF),
|
299
|
+
(0x8FFFE..0x8FFFF),
|
300
|
+
(0x9FFFE..0x9FFFF),
|
301
|
+
(0xAFFFE..0xAFFFF),
|
302
|
+
(0xBFFFE..0xBFFFF),
|
303
|
+
(0xCFFFE..0xCFFFF),
|
304
|
+
(0xDFFFE..0xDFFFF),
|
305
|
+
(0xEFFFE..0xEFFFF),
|
306
|
+
(0xFFFFE..0xFFFFF),
|
307
|
+
(0x10FFFE..0x10FFFF)
|
308
|
+
].freeze
|
309
|
+
|
235
310
|
def value
|
236
311
|
ESCAPES.fetch(string) do
|
237
|
-
|
312
|
+
code = string.sub(/\Au\{?([A-F0-9]+)\}?/, "\\1").to_i(16)
|
313
|
+
NON_CHARACTERS.each do |range|
|
314
|
+
raise Citrus::ParseError, input if range.include?(code)
|
315
|
+
end
|
316
|
+
[code].pack("U*")
|
238
317
|
end
|
239
318
|
end
|
240
319
|
end
|
241
320
|
|
242
321
|
module SingleQuoteLiteral
|
243
322
|
def value
|
244
|
-
chunks = capture(:single_quote_continue).value
|
245
|
-
|
246
|
-
|
247
|
-
|
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
|
326
|
+
indent = Util.indent_size(chunks.join)
|
248
327
|
|
249
328
|
TextLiteral.for(
|
250
329
|
*chunks
|
251
|
-
|
252
|
-
|
330
|
+
.chunk { |c| c != "\n" }
|
331
|
+
.flat_map { |(line, chunk)| line ? chunk[indent..-1] : chunk }
|
253
332
|
)
|
254
333
|
end
|
255
334
|
end
|
@@ -260,6 +339,12 @@ module Dhall
|
|
260
339
|
end
|
261
340
|
end
|
262
341
|
|
342
|
+
module EndOfLine
|
343
|
+
def value
|
344
|
+
"\n"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
263
348
|
module Interpolation
|
264
349
|
def value
|
265
350
|
capture(:complete_expression).value
|
@@ -284,18 +369,21 @@ module Dhall
|
|
284
369
|
end
|
285
370
|
end
|
286
371
|
|
287
|
-
module
|
372
|
+
module Variable
|
288
373
|
def value
|
289
|
-
|
374
|
+
Dhall::Variable.new(
|
375
|
+
name: capture(:nonreserved_label).value,
|
376
|
+
index: capture(:natural_literal)&.string.to_i
|
377
|
+
)
|
378
|
+
end
|
379
|
+
end
|
290
380
|
|
291
|
-
|
292
|
-
|
381
|
+
module Builtin
|
382
|
+
def value
|
383
|
+
return Dhall::Bool.new(value: true) if string == "True"
|
384
|
+
return Dhall::Bool.new(value: false) if string == "False"
|
293
385
|
|
294
|
-
Dhall::Builtins
|
295
|
-
Variable.new(
|
296
|
-
name: name,
|
297
|
-
index: capture(:natural_literal)&.string.to_i
|
298
|
-
)
|
386
|
+
Dhall::Builtins[string.to_sym]
|
299
387
|
end
|
300
388
|
end
|
301
389
|
|
@@ -304,7 +392,7 @@ module Dhall
|
|
304
392
|
key = [
|
305
393
|
:complete_expression,
|
306
394
|
:record_type_or_literal,
|
307
|
-
:
|
395
|
+
:union_type
|
308
396
|
].find { |k| captures.key?(k) }
|
309
397
|
key ? capture(key).value : super
|
310
398
|
end
|
@@ -316,31 +404,6 @@ module Dhall
|
|
316
404
|
end
|
317
405
|
end
|
318
406
|
|
319
|
-
module UnionTypeOrLiteralVariantType
|
320
|
-
def value(label)
|
321
|
-
rest = capture(:non_empty_union_type_or_literal)&.value
|
322
|
-
type = UnionType.new(
|
323
|
-
alternatives: { label => capture(:expression)&.value }
|
324
|
-
)
|
325
|
-
if rest.is_a?(Union)
|
326
|
-
rest.with(alternatives: type.merge(rest.alternatives))
|
327
|
-
else
|
328
|
-
rest ? type.merge(rest) : type
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
module UnionLiteralVariantValue
|
334
|
-
def value(label)
|
335
|
-
Union.new(
|
336
|
-
tag: label,
|
337
|
-
value: capture(:expression).value,
|
338
|
-
alternatives: captures(:union_type_entry).map(&:value)
|
339
|
-
.reduce(UnionType.new(alternatives: {}), &:merge)
|
340
|
-
)
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
407
|
module UnionTypeEntry
|
345
408
|
def value
|
346
409
|
UnionType.new(
|
@@ -351,19 +414,9 @@ module Dhall
|
|
351
414
|
end
|
352
415
|
end
|
353
416
|
|
354
|
-
module
|
417
|
+
module NonEmptyUnionType
|
355
418
|
def value
|
356
|
-
|
357
|
-
:union_literal_variant_value,
|
358
|
-
:union_type_or_literal_variant_type
|
359
|
-
].find { |k| captures.key?(k) }
|
360
|
-
|
361
|
-
if key
|
362
|
-
capture(key).value(capture(:any_label).value)
|
363
|
-
else
|
364
|
-
no_alts = UnionType.new(alternatives: {})
|
365
|
-
Union.from(no_alts, capture(:any_label).value, nil)
|
366
|
-
end
|
419
|
+
captures(:union_type_entry).map(&:value).reduce(&:merge)
|
367
420
|
end
|
368
421
|
end
|
369
422
|
|
@@ -421,25 +474,6 @@ module Dhall
|
|
421
474
|
|
422
475
|
RecordTypeEntry = RecordLiteralEntry
|
423
476
|
|
424
|
-
module EmptyCollection
|
425
|
-
def value
|
426
|
-
if captures.key?(:list)
|
427
|
-
EmptyList.new(element_type: capture(:import_expression).value)
|
428
|
-
else
|
429
|
-
OptionalNone.new(value_type: capture(:import_expression).value)
|
430
|
-
end
|
431
|
-
end
|
432
|
-
end
|
433
|
-
|
434
|
-
module NonEmptyOptional
|
435
|
-
def value
|
436
|
-
Optional.new(
|
437
|
-
value: capture(:expression).value,
|
438
|
-
value_type: capture(:import_expression).value
|
439
|
-
)
|
440
|
-
end
|
441
|
-
end
|
442
|
-
|
443
477
|
module AnnotatedExpression
|
444
478
|
def value
|
445
479
|
if matches[1].string.empty?
|
@@ -468,6 +502,8 @@ module Dhall
|
|
468
502
|
def value
|
469
503
|
import_type = if captures.key?(:text)
|
470
504
|
Dhall::Import::Text
|
505
|
+
elsif captures.key?(:location)
|
506
|
+
Dhall::Import::AsLocation
|
471
507
|
else
|
472
508
|
Dhall::Import::Expression
|
473
509
|
end
|
@@ -487,7 +523,28 @@ module Dhall
|
|
487
523
|
module Hash
|
488
524
|
def value
|
489
525
|
protocol, data = string.split(/:/, 2)
|
490
|
-
Dhall::Import::IntegrityCheck.new(
|
526
|
+
Dhall::Import::IntegrityCheck.new(
|
527
|
+
code: Multihashes::TABLE.key(
|
528
|
+
protocol.sub(/\Asha(\d{3})/, "sha2-\\1")
|
529
|
+
),
|
530
|
+
digest: [data].pack("H*")
|
531
|
+
)
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
module Scheme
|
536
|
+
def value
|
537
|
+
::URI.scheme_list[string.upcase]
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
module Authority
|
542
|
+
def value
|
543
|
+
{
|
544
|
+
userinfo: capture(:userinfo)&.value,
|
545
|
+
host: capture(:host).value,
|
546
|
+
port: capture(:port)&.value
|
547
|
+
}
|
491
548
|
end
|
492
549
|
end
|
493
550
|
|
@@ -497,23 +554,24 @@ module Dhall
|
|
497
554
|
"https" => Dhall::Import::Https
|
498
555
|
}.freeze
|
499
556
|
|
557
|
+
def http(key)
|
558
|
+
@http ||= capture(:http_raw)
|
559
|
+
@http.capture(key)&.value
|
560
|
+
end
|
561
|
+
|
500
562
|
def value
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
*unescaped_components,
|
506
|
-
http.capture(:query)&.value
|
563
|
+
uri = http(:scheme).build(
|
564
|
+
http(:authority).merge(
|
565
|
+
path: http(:url_path) || "/"
|
566
|
+
)
|
507
567
|
)
|
508
|
-
end
|
509
568
|
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
end
|
569
|
+
uri.instance_variable_set(:@query, http(:query))
|
570
|
+
|
571
|
+
SCHEME.fetch(uri.scheme).new(
|
572
|
+
headers: capture(:import_expression)&.value,
|
573
|
+
uri: uri
|
574
|
+
)
|
517
575
|
end
|
518
576
|
end
|
519
577
|
|
@@ -521,9 +579,9 @@ module Dhall
|
|
521
579
|
def value
|
522
580
|
Dhall::Import::EnvironmentVariable.new(
|
523
581
|
if captures.key?(:bash_environment_variable)
|
524
|
-
capture(:bash_environment_variable).
|
582
|
+
capture(:bash_environment_variable).value
|
525
583
|
else
|
526
|
-
capture(:posix_environment_variable).value
|
584
|
+
capture(:posix_environment_variable).value
|
527
585
|
end
|
528
586
|
)
|
529
587
|
end
|
@@ -531,12 +589,22 @@ module Dhall
|
|
531
589
|
|
532
590
|
module PosixEnvironmentVariable
|
533
591
|
def value
|
534
|
-
matches.map(&:value).join
|
592
|
+
matches.map(&:value).join.encode(Encoding::UTF_8)
|
535
593
|
end
|
536
594
|
end
|
537
595
|
|
538
596
|
module PosixEnvironmentVariableCharacter
|
539
|
-
ESCAPES =
|
597
|
+
ESCAPES = {
|
598
|
+
"\"" => "\"",
|
599
|
+
"\\" => "\\",
|
600
|
+
"a" => "\a",
|
601
|
+
"b" => "\b",
|
602
|
+
"f" => "\f",
|
603
|
+
"n" => "\n",
|
604
|
+
"r" => "\r",
|
605
|
+
"t" => "\t",
|
606
|
+
"v" => "\v"
|
607
|
+
}.freeze
|
540
608
|
|
541
609
|
def value
|
542
610
|
if first&.string == "\\"
|
@@ -580,15 +648,28 @@ module Dhall
|
|
580
648
|
end
|
581
649
|
|
582
650
|
module PathComponent
|
583
|
-
def value(
|
651
|
+
def value(escaper=:itself.to_proc)
|
584
652
|
if captures.key?(:quoted_path_component)
|
585
|
-
capture(:quoted_path_component).value
|
653
|
+
escaper.call(capture(:quoted_path_component).value)
|
586
654
|
else
|
587
|
-
|
655
|
+
capture(:unquoted_path_component).value
|
588
656
|
end
|
589
657
|
end
|
590
658
|
end
|
591
659
|
|
660
|
+
module UrlPath
|
661
|
+
def value
|
662
|
+
"/" + matches.map { |pc|
|
663
|
+
if pc.captures.key?(:path_component)
|
664
|
+
# We escape here because ruby stdlib URI just stores path unparsed
|
665
|
+
pc.value(Util.method(:uri_escape))
|
666
|
+
else
|
667
|
+
pc.string[1..-1]
|
668
|
+
end
|
669
|
+
}.join("/")
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
592
673
|
module Missing
|
593
674
|
def value
|
594
675
|
Dhall::Import::MissingImport.new
|