dhall 0.3.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/dhall/parser.rb CHANGED
@@ -21,23 +21,21 @@ module Dhall
21
21
 
22
22
  module Expression
23
23
  def value
24
- key =
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
- [:empty_collection, :non_empty_optional]
27
+ [:let_binding, :lambda, :forall, :arrow, :if, :merge, :tomap, :assert]
32
28
  .find { |k| captures.key?(k) }
33
- key ? capture(key).value : super
29
+
30
+ key ? public_send(key) : super
34
31
  end
35
32
 
36
33
  def let_binding
37
- LetBlock.for(
38
- lets: captures(:let_binding).map(&:value),
39
- body: capture(:expression).value
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(
@@ -122,9 +136,9 @@ module Dhall
122
136
  if captures.key?(:merge)
123
137
  merge
124
138
  elsif captures.key?(:some)
125
- Optional.new(
126
- value: capture(:import_expression).value
127
- )
139
+ Optional.new(value: capture(:import_expression).value)
140
+ elsif captures.key?(:tomap)
141
+ ToMap.new(record: capture(:import_expression).value)
128
142
  else
129
143
  super
130
144
  end
@@ -142,11 +156,11 @@ module Dhall
142
156
  module SelectorExpression
143
157
  def value
144
158
  record = capture(:primitive_expression).value
145
- selectors = captures(:selector).map(&:value)
146
- selectors.reduce(record) do |rec, sels|
159
+ captures(:selector).map(&:value).reduce(record) do |rec, sels|
147
160
  if sels.is_a?(Array)
148
- return EmptyRecordProjection.new(record: rec) if sels.empty?
149
- RecordProjection.new(record: rec, selectors: sels)
161
+ RecordProjection.for(rec, sels)
162
+ elsif sels.is_a?(Dhall::Expression)
163
+ RecordProjectionByExpression.new(record: rec, selector: sels)
150
164
  else
151
165
  RecordSelection.new(record: rec, selector: sels)
152
166
  end
@@ -154,9 +168,15 @@ module Dhall
154
168
  end
155
169
  end
156
170
 
157
- module Labels
171
+ module Selector
158
172
  def value
159
- captures(:any_label).map(&:value)
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
160
180
  end
161
181
  end
162
182
 
@@ -237,7 +257,7 @@ module Dhall
237
257
  .map(&:value)
238
258
  .chunk { |s| s.is_a?(String) }
239
259
  .flat_map do |(strs, group)|
240
- strs ? group.map { |s| s.encode("UTF-16BE") }.join : group
260
+ strs ? group.join : group
241
261
  end
242
262
  )
243
263
  end
@@ -266,20 +286,44 @@ module Dhall
266
286
  "t" => "\t"
267
287
  }.freeze
268
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
+
269
310
  def value
270
311
  ESCAPES.fetch(string) do
271
- [string[1..-1]].pack("H*").force_encoding("UTF-16BE")
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*")
272
317
  end
273
318
  end
274
319
  end
275
320
 
276
321
  module SingleQuoteLiteral
277
322
  def value
278
- chunks = capture(:single_quote_continue).value
279
- raw = chunks.join
280
- indent = raw.scan(/^[ \t]*(?=[^ \t\r\n])/).map(&:chars)
281
- .reduce(&Util.method(:longest_common_prefix)).length
282
- indent = 0 if raw.end_with?("\n")
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)
283
327
 
284
328
  TextLiteral.for(
285
329
  *chunks
@@ -295,6 +339,12 @@ module Dhall
295
339
  end
296
340
  end
297
341
 
342
+ module EndOfLine
343
+ def value
344
+ "\n"
345
+ end
346
+ end
347
+
298
348
  module Interpolation
299
349
  def value
300
350
  capture(:complete_expression).value
@@ -342,7 +392,7 @@ module Dhall
342
392
  key = [
343
393
  :complete_expression,
344
394
  :record_type_or_literal,
345
- :union_type_or_literal
395
+ :union_type
346
396
  ].find { |k| captures.key?(k) }
347
397
  key ? capture(key).value : super
348
398
  end
@@ -354,31 +404,6 @@ module Dhall
354
404
  end
355
405
  end
356
406
 
357
- module UnionTypeOrLiteralVariantType
358
- def value(label)
359
- rest = capture(:non_empty_union_type_or_literal)&.value
360
- type = UnionType.new(
361
- alternatives: { label => capture(:expression)&.value }
362
- )
363
- if rest.is_a?(Union)
364
- rest.with(alternatives: type.merge(rest.alternatives))
365
- else
366
- rest ? type.merge(rest) : type
367
- end
368
- end
369
- end
370
-
371
- module UnionLiteralVariantValue
372
- def value(label)
373
- Union.new(
374
- tag: label,
375
- value: capture(:expression).value,
376
- alternatives: captures(:union_type_entry).map(&:value)
377
- .reduce(UnionType.new(alternatives: {}), &:merge)
378
- )
379
- end
380
- end
381
-
382
407
  module UnionTypeEntry
383
408
  def value
384
409
  UnionType.new(
@@ -389,19 +414,9 @@ module Dhall
389
414
  end
390
415
  end
391
416
 
392
- module NonEmptyUnionTypeOrLiteral
417
+ module NonEmptyUnionType
393
418
  def value
394
- key = [
395
- :union_literal_variant_value,
396
- :union_type_or_literal_variant_type
397
- ].find { |k| captures.key?(k) }
398
-
399
- if key
400
- capture(key).value(capture(:any_label).value)
401
- else
402
- no_alts = UnionType.new(alternatives: {})
403
- Union.from(no_alts, capture(:any_label).value, nil)
404
- end
419
+ captures(:union_type_entry).map(&:value).reduce(&:merge)
405
420
  end
406
421
  end
407
422
 
@@ -459,25 +474,6 @@ module Dhall
459
474
 
460
475
  RecordTypeEntry = RecordLiteralEntry
461
476
 
462
- module EmptyCollection
463
- def value
464
- if captures.key?(:list)
465
- EmptyList.new(element_type: capture(:import_expression).value)
466
- else
467
- OptionalNone.new(value_type: capture(:import_expression).value)
468
- end
469
- end
470
- end
471
-
472
- module NonEmptyOptional
473
- def value
474
- Optional.new(
475
- value: capture(:expression).value,
476
- value_type: capture(:import_expression).value
477
- )
478
- end
479
- end
480
-
481
477
  module AnnotatedExpression
482
478
  def value
483
479
  if matches[1].string.empty?
@@ -506,6 +502,8 @@ module Dhall
506
502
  def value
507
503
  import_type = if captures.key?(:text)
508
504
  Dhall::Import::Text
505
+ elsif captures.key?(:location)
506
+ Dhall::Import::AsLocation
509
507
  else
510
508
  Dhall::Import::Expression
511
509
  end
@@ -525,7 +523,28 @@ module Dhall
525
523
  module Hash
526
524
  def value
527
525
  protocol, data = string.split(/:/, 2)
528
- Dhall::Import::IntegrityCheck.new(protocol, data)
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
+ }
529
548
  end
530
549
  end
531
550
 
@@ -535,23 +554,24 @@ module Dhall
535
554
  "https" => Dhall::Import::Https
536
555
  }.freeze
537
556
 
557
+ def http(key)
558
+ @http ||= capture(:http_raw)
559
+ @http.capture(key)&.value
560
+ end
561
+
538
562
  def value
539
- http = capture(:http_raw)
540
- SCHEME.fetch(http.capture(:scheme).value).new(
541
- capture(:import_hashed)&.value(Dhall::Import::Expression),
542
- http.capture(:authority).value,
543
- *unescaped_components,
544
- http.capture(:query)&.value
563
+ uri = http(:scheme).build(
564
+ http(:authority).merge(
565
+ path: http(:url_path) || "/"
566
+ )
545
567
  )
546
- end
547
568
 
548
- def unescaped_components
549
- capture(:http_raw)
550
- .capture(:path)
551
- .captures(:path_component)
552
- .map do |pc|
553
- pc.value(URI.method(:unescape))
554
- 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
+ )
555
575
  end
556
576
  end
557
577
 
@@ -628,15 +648,28 @@ module Dhall
628
648
  end
629
649
 
630
650
  module PathComponent
631
- def value(unescaper=:itself.to_proc)
651
+ def value(escaper=:itself.to_proc)
632
652
  if captures.key?(:quoted_path_component)
633
- capture(:quoted_path_component).value
653
+ escaper.call(capture(:quoted_path_component).value)
634
654
  else
635
- unescaper.call(capture(:unquoted_path_component).value)
655
+ capture(:unquoted_path_component).value
636
656
  end
637
657
  end
638
658
  end
639
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
+
640
673
  module Missing
641
674
  def value
642
675
  Dhall::Import::MissingImport.new
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
- 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
@@ -38,16 +38,10 @@ module Dhall
38
38
  req["Origin"] = parent_origin
39
39
  req["Access-Control-Request-Method"] = "GET"
40
40
  req["Access-Control-Request-Headers"] =
41
- source.headers.map { |h| h.fetch("header").to_s }.join(",")
42
- r = Net::HTTP.start(
43
- uri.hostname,
44
- uri.port,
45
- use_ssl: uri.scheme == "https",
46
- open_timeout: timeout,
47
- ssl_timeout: timeout,
48
- read_timeout: timeout,
49
- write_timeout: timeout
50
- ) { |http| http.request(req) }
41
+ source.headers.to_a.map { |h|
42
+ (h.fetch("header") { h.fetch("mapKey") }).to_s
43
+ }.join(",")
44
+ r = Util.net_http_req_with_timeout(uri, req, timeout: timeout)
51
45
 
52
46
  raise ImportFailedException, source if r.code != "200"
53
47
  unless r["Access-Control-Allow-Origin"] == parent_origin ||
@@ -59,23 +53,21 @@ module Dhall
59
53
 
60
54
  ReadHttpSources = lambda do |sources, parent_origin|
61
55
  sources.map do |source|
62
- Promise.resolve(nil).then do
56
+ Util::LazyPromise.new do
63
57
  PreflightCORS.call(source, parent_origin)
64
58
  timeout = source.deadline.timeout
65
59
  uri = source.uri
66
- req = Net::HTTP::Get.new(uri)
67
- source.headers.each do |header|
68
- req[header.fetch("header").to_s] = header.fetch("value").to_s
60
+ r = loop do
61
+ req = Net::HTTP::Get.new(uri)
62
+ source.headers.each do |header|
63
+ req[(header.fetch("header") { header.fetch("mapKey") }).to_s] =
64
+ (header.fetch("value") { header.fetch("mapValue") }).to_s
65
+ end
66
+ r = Util.net_http_req_with_timeout(uri, req, timeout: timeout)
67
+
68
+ break r unless ["301", "302", "303", "307", "308"].include?(r.code)
69
+ uri = URI(r["Location"])
69
70
  end
70
- r = Net::HTTP.start(
71
- uri.hostname,
72
- uri.port,
73
- use_ssl: uri.scheme == "https",
74
- open_timeout: timeout,
75
- ssl_timeout: timeout,
76
- read_timeout: timeout,
77
- write_timeout: timeout
78
- ) { |http| http.request(req) }
79
71
 
80
72
  raise ImportFailedException, source if r.code != "200"
81
73
  r.body
@@ -86,7 +78,7 @@ module Dhall
86
78
  StandardReadHttpSources = lambda do |sources, parent_origin|
87
79
  ReadHttpSources.call(sources, parent_origin).map do |source_promise|
88
80
  source_promise.then do |s|
89
- s = s.force_encoding("UTF-8")
81
+ s = s.dup.force_encoding("UTF-8")
90
82
  unless s.valid_encoding?
91
83
  raise ImportFailedException, "#{s.inspect} is not valid UTF-8"
92
84
  end
@@ -106,7 +98,7 @@ module Dhall
106
98
  path_reader: ReadPathSources,
107
99
  http_reader: ReadHttpSources,
108
100
  https_reader: http_reader,
109
- public_gateway: "cloudflare-ipfs.com"
101
+ public_gateway: URI("https://cloudflare-ipfs.com")
110
102
  )
111
103
  @path_reader = path_reader
112
104
  @http_reader = http_reader
@@ -139,7 +131,7 @@ module Dhall
139
131
  def gateway_fallback(source, promise)
140
132
  promise.catch {
141
133
  @http_reader.call([
142
- source.to_uri(Import::Http, "localhost:8000")
134
+ source.to_uri(Import::Http, URI("http://localhost:8000"))
143
135
  ], "localhost").first
144
136
  }.catch do
145
137
  @https_reader.call([
@@ -182,11 +174,11 @@ module Dhall
182
174
 
183
175
  def fetch(key, &block)
184
176
  if key.is_a?(String) && key.start_with?("sha256:")
185
- file = @dir + key.sub(/^sha256:/, "")
177
+ file = @dir + key.sub(/^sha256:/, "1220")
186
178
  return Dhall.from_binary(file.binread) if file.exist?
187
179
 
188
180
  Promise.resolve(nil).then(&block).then do |result|
189
- file.open("wb") { |fh| fh.write(result.to_binary) }
181
+ file.open("wb") { |fh| fh.write(result.to_cbor) }
190
182
  result
191
183
  end
192
184
  else
@@ -359,7 +351,7 @@ module Dhall
359
351
  http_reader: ReadHttpSources,
360
352
  https_reader: http_reader,
361
353
  environment_reader: ReadEnvironmentSources,
362
- ipfs_public_gateway: "cloudflare-ipfs.com",
354
+ ipfs_public_gateway: URI("https://cloudflare-ipfs.com"),
363
355
  cache: RamCache.new,
364
356
  max_depth: 50
365
357
  )
@@ -427,9 +419,25 @@ module Dhall
427
419
  ).then { |h| @expr.with(h) }
428
420
  end
429
421
 
422
+ class ImportAsLocationResolver < ExpressionResolver
423
+ def resolve(resolver:, relative_to:)
424
+ Promise.resolve(nil).then do
425
+ @expr.real_path(relative_to).location
426
+ end
427
+ end
428
+ end
429
+
430
430
  class ImportResolver < ExpressionResolver
431
431
  register_for Import
432
432
 
433
+ def self.new(expr)
434
+ if expr.import_type == Import::AsLocation
435
+ ImportAsLocationResolver.new(expr)
436
+ else
437
+ super
438
+ end
439
+ end
440
+
433
441
  def resolve(resolver:, relative_to:)
434
442
  Promise.resolve(nil).then do
435
443
  resolver.cache_fetch(@expr.cache_key(relative_to)) do
@@ -441,7 +449,9 @@ module Dhall
441
449
  def resolve_raw(resolver:, relative_to:)
442
450
  real_path = @expr.real_path(relative_to)
443
451
  real_path.resolve(resolver).then do |result|
444
- @expr.parse_and_check(result, deadline: resolver.deadline).resolve(
452
+ @expr.parse_resolve_check(
453
+ result,
454
+ deadline: resolver.deadline,
445
455
  resolver: resolver.child(real_path),
446
456
  relative_to: real_path
447
457
  )