dhall 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|