dhall 0.3.0 → 0.4.0
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 +4 -4
- data/bin/dhall-compile +38 -4
- data/bin/json-to-dhall +1 -1
- data/bin/yaml-to-dhall +1 -1
- data/dhall.gemspec +3 -0
- data/lib/dhall.rb +1 -0
- data/lib/dhall/as_dhall.rb +6 -0
- data/lib/dhall/ast.rb +215 -86
- data/lib/dhall/binary.rb +80 -11
- data/lib/dhall/builtins.rb +162 -241
- data/lib/dhall/coder.rb +6 -1
- data/lib/dhall/normalize.rb +30 -4
- data/lib/dhall/parser.citrus +51 -30
- data/lib/dhall/parser.rb +119 -59
- data/lib/dhall/resolve.rb +36 -28
- data/lib/dhall/typecheck.rb +86 -14
- data/lib/dhall/types.rb +19 -0
- data/lib/dhall/util.rb +31 -0
- metadata +45 -2
data/lib/dhall/resolve.rb
CHANGED
@@ -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|
|
42
|
-
|
43
|
-
|
44
|
-
|
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 ||
|
@@ -63,19 +57,17 @@ module Dhall
|
|
63
57
|
PreflightCORS.call(source, parent_origin)
|
64
58
|
timeout = source.deadline.timeout
|
65
59
|
uri = source.uri
|
66
|
-
|
67
|
-
|
68
|
-
|
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.
|
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
|
data/lib/dhall/typecheck.rb
CHANGED
@@ -12,7 +12,7 @@ module Dhall
|
|
12
12
|
|
13
13
|
def self.assert_type(expr, assertion, message, context:)
|
14
14
|
aexpr = self.for(expr).annotate(context)
|
15
|
-
type = aexpr.type
|
15
|
+
type = aexpr.type.normalize
|
16
16
|
raise TypeError, "#{message}: #{type}" unless assertion === type
|
17
17
|
aexpr
|
18
18
|
end
|
@@ -40,9 +40,13 @@ module Dhall
|
|
40
40
|
@typecheckers[node_type] ||= [typechecker, extras]
|
41
41
|
end
|
42
42
|
|
43
|
-
def self.
|
43
|
+
def self.annotate(expr)
|
44
44
|
return if expr.nil?
|
45
|
-
TypeChecker.for(expr).annotate(TypeChecker::Context.new)
|
45
|
+
TypeChecker.for(expr).annotate(TypeChecker::Context.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.type_of(expr)
|
49
|
+
annotate(expr)&.type
|
46
50
|
end
|
47
51
|
|
48
52
|
class Context
|
@@ -358,10 +362,16 @@ module Dhall
|
|
358
362
|
TypeChecker.register self, Dhall::EmptyList
|
359
363
|
|
360
364
|
def initialize(expr)
|
361
|
-
@expr = expr
|
365
|
+
@expr = expr.with(type: expr.type.normalize)
|
362
366
|
end
|
363
367
|
|
364
368
|
def annotate(context)
|
369
|
+
TypeChecker.assert @expr.type, Dhall::Application,
|
370
|
+
"EmptyList unknown type #{@expr.type.inspect}"
|
371
|
+
|
372
|
+
TypeChecker.assert @expr.type.function, Builtins[:List],
|
373
|
+
"EmptyList unknown type #{@expr.type.inspect}"
|
374
|
+
|
365
375
|
TypeChecker.assert_type @expr.element_type, Builtins[:Type],
|
366
376
|
"EmptyList element type not of type Type",
|
367
377
|
context: context
|
@@ -383,7 +393,7 @@ module Dhall
|
|
383
393
|
end
|
384
394
|
|
385
395
|
def annotation
|
386
|
-
list = @alist.with(
|
396
|
+
list = @alist.with(type: Builtins[:List].call(element_type))
|
387
397
|
Dhall::TypeAnnotation.new(type: list.type, value: list)
|
388
398
|
end
|
389
399
|
|
@@ -537,12 +547,13 @@ module Dhall
|
|
537
547
|
|
538
548
|
class Selector
|
539
549
|
def self.for(annotated_record)
|
540
|
-
|
550
|
+
typ = annotated_record.type.normalize
|
551
|
+
if KINDS.include?(typ)
|
541
552
|
TypeSelector.new(annotated_record.value)
|
542
|
-
elsif
|
543
|
-
new(
|
553
|
+
elsif typ.class == Dhall::RecordType
|
554
|
+
new(typ)
|
544
555
|
else
|
545
|
-
raise TypeError, "RecordSelection on #{
|
556
|
+
raise TypeError, "RecordSelection on #{typ}"
|
546
557
|
end
|
547
558
|
end
|
548
559
|
|
@@ -604,6 +615,33 @@ module Dhall
|
|
604
615
|
end
|
605
616
|
end
|
606
617
|
|
618
|
+
class RecordProjectionByExpression
|
619
|
+
TypeChecker.register self, Dhall::RecordProjectionByExpression
|
620
|
+
|
621
|
+
def initialize(projection)
|
622
|
+
@selector = projection.selector.normalize
|
623
|
+
@project_by_expression = projection
|
624
|
+
@project_by_keys = Dhall::RecordProjection.for(
|
625
|
+
@project_by_expression.record,
|
626
|
+
@selector.keys
|
627
|
+
)
|
628
|
+
end
|
629
|
+
|
630
|
+
def annotate(context)
|
631
|
+
TypeChecker.assert @selector, Dhall::RecordType,
|
632
|
+
"RecordProjectionByExpression on #{@selector.class}"
|
633
|
+
|
634
|
+
TypeChecker.assert_type @project_by_keys, @selector,
|
635
|
+
"Type doesn't match #{@selector}",
|
636
|
+
context: context
|
637
|
+
|
638
|
+
Dhall::TypeAnnotation.new(
|
639
|
+
value: @project_by_expression,
|
640
|
+
type: @selector
|
641
|
+
)
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
607
645
|
class Enum
|
608
646
|
TypeChecker.register self, Dhall::Enum
|
609
647
|
|
@@ -648,6 +686,39 @@ module Dhall
|
|
648
686
|
end
|
649
687
|
end
|
650
688
|
|
689
|
+
class ToMap
|
690
|
+
TypeChecker.register self, Dhall::ToMap
|
691
|
+
|
692
|
+
def initialize(tomap)
|
693
|
+
@tomap = tomap
|
694
|
+
@record = TypeChecker.for(tomap.record)
|
695
|
+
end
|
696
|
+
|
697
|
+
def check_annotation(record_type)
|
698
|
+
if record_type.is_a?(Dhall::EmptyRecordType)
|
699
|
+
TypeChecker.assert @tomap.type, Dhall::Expression,
|
700
|
+
"toMap {=} has no annotation"
|
701
|
+
else
|
702
|
+
t = Types::MAP(v: record_type.record.values.first)
|
703
|
+
|
704
|
+
TypeChecker.assert t, (@tomap.type || t),
|
705
|
+
"toMap does not match annotation"
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
def annotate(context)
|
710
|
+
record_type = @record.annotate(context).type
|
711
|
+
TypeChecker.assert record_type, Dhall::RecordType,
|
712
|
+
"toMap on a non-record: #{record_type.inspect}"
|
713
|
+
|
714
|
+
TypeChecker.assert record_type.record.values, Util::ArrayAllTheSame,
|
715
|
+
"toMap heterogenous: #{record_type.inspect}"
|
716
|
+
|
717
|
+
type = check_annotation(record_type)
|
718
|
+
Dhall::TypeAnnotation.new(value: @tomap, type: type)
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
651
722
|
class Merge
|
652
723
|
TypeChecker.register self, Dhall::Merge
|
653
724
|
|
@@ -1209,12 +1280,13 @@ module Dhall
|
|
1209
1280
|
TypeChecker.register self, Dhall::Builtin
|
1210
1281
|
|
1211
1282
|
def self.for(builtin)
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
new(builtin)
|
1283
|
+
if builtin.is_a?(Dhall::BuiltinFunction)
|
1284
|
+
if (unfilled = builtin.unfill) != builtin
|
1285
|
+
return TypeChecker.for(unfilled)
|
1286
|
+
end
|
1217
1287
|
end
|
1288
|
+
|
1289
|
+
new(builtin)
|
1218
1290
|
end
|
1219
1291
|
|
1220
1292
|
def initialize(builtin)
|
data/lib/dhall/types.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dhall/builtins"
|
4
|
+
|
5
|
+
module Dhall
|
6
|
+
module Types
|
7
|
+
def self.MAP_ENTRY(k: Builtins[:Text], v: Builtins[:Text])
|
8
|
+
RecordType.new(
|
9
|
+
record: {
|
10
|
+
"mapKey" => k, "mapValue" => v
|
11
|
+
}
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.MAP(k: Builtins[:Text], v: Builtins[:Text])
|
16
|
+
Builtins[:List].call(MAP_ENTRY(k: k, v: v))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/dhall/util.rb
CHANGED
@@ -181,5 +181,36 @@ module Dhall
|
|
181
181
|
def self.longest_common_prefix(a, b)
|
182
182
|
a.zip(b).take_while { |(x, y)| x == y }.map(&:first)
|
183
183
|
end
|
184
|
+
|
185
|
+
def self.indent_size(str)
|
186
|
+
if str.end_with?("\n")
|
187
|
+
0
|
188
|
+
else
|
189
|
+
str
|
190
|
+
.scan(/^[ \t]*(?=[^ \t\n]|\Z)/)
|
191
|
+
.map(&:chars)
|
192
|
+
.reduce(&method(:longest_common_prefix))&.length.to_i
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.path_components_to_uri(*components)
|
197
|
+
URI("/#{components.map(&method(:uri_escape)).join("/")}")
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.uri_escape(s)
|
201
|
+
::URI.encode_www_form_component(s).gsub("+", "%20")
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.net_http_req_with_timeout(uri, req, timeout:)
|
205
|
+
Net::HTTP.start(
|
206
|
+
uri.hostname,
|
207
|
+
uri.port,
|
208
|
+
use_ssl: uri.scheme == "https",
|
209
|
+
open_timeout: timeout,
|
210
|
+
ssl_timeout: timeout,
|
211
|
+
read_timeout: timeout,
|
212
|
+
write_timeout: timeout
|
213
|
+
) { |http| http.request(req) }
|
214
|
+
end
|
184
215
|
end
|
185
216
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dhall
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.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-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: base32
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.2
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: cbor
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,34 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: lazy_object
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: multihashes
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.3
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.1.3
|
41
83
|
- !ruby/object:Gem::Dependency
|
42
84
|
name: promise.rb
|
43
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,6 +179,7 @@ files:
|
|
137
179
|
- lib/dhall/parser.rb
|
138
180
|
- lib/dhall/resolve.rb
|
139
181
|
- lib/dhall/typecheck.rb
|
182
|
+
- lib/dhall/types.rb
|
140
183
|
- lib/dhall/util.rb
|
141
184
|
- lib/dhall/visitor.rb
|
142
185
|
homepage: https://git.sr.ht/~singpolyma/dhall-ruby
|