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/resolve.rb
CHANGED
@@ -16,23 +16,32 @@ 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
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
ReadEnvironmentSources = lambda do |sources|
|
24
|
+
sources.map do |source|
|
25
|
+
Util::LazyPromise.new do
|
26
|
+
ENV.fetch(source.var) do
|
27
|
+
raise ImportFailedException, "No #{source}"
|
28
|
+
end
|
29
|
+
end
|
20
30
|
end
|
21
31
|
end
|
22
32
|
|
23
33
|
PreflightCORS = lambda do |source, parent_origin|
|
34
|
+
timeout = source.deadline.timeout
|
24
35
|
uri = source.uri
|
25
36
|
if parent_origin != "localhost" && parent_origin != source.origin
|
26
37
|
req = Net::HTTP::Options.new(uri)
|
27
38
|
req["Origin"] = parent_origin
|
28
39
|
req["Access-Control-Request-Method"] = "GET"
|
29
40
|
req["Access-Control-Request-Headers"] =
|
30
|
-
source.headers.map { |h|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
use_ssl: uri.scheme == "https"
|
35
|
-
) { |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)
|
36
45
|
|
37
46
|
raise ImportFailedException, source if r.code != "200"
|
38
47
|
unless r["Access-Control-Allow-Origin"] == parent_origin ||
|
@@ -44,18 +53,21 @@ module Dhall
|
|
44
53
|
|
45
54
|
ReadHttpSources = lambda do |sources, parent_origin|
|
46
55
|
sources.map do |source|
|
47
|
-
|
56
|
+
Util::LazyPromise.new do
|
48
57
|
PreflightCORS.call(source, parent_origin)
|
58
|
+
timeout = source.deadline.timeout
|
49
59
|
uri = source.uri
|
50
|
-
|
51
|
-
|
52
|
-
|
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"])
|
53
70
|
end
|
54
|
-
r = Net::HTTP.start(
|
55
|
-
uri.hostname,
|
56
|
-
uri.port,
|
57
|
-
use_ssl: uri.scheme == "https"
|
58
|
-
) { |http| http.request(req) }
|
59
71
|
|
60
72
|
raise ImportFailedException, source if r.code != "200"
|
61
73
|
r.body
|
@@ -63,6 +75,18 @@ module Dhall
|
|
63
75
|
end
|
64
76
|
end
|
65
77
|
|
78
|
+
StandardReadHttpSources = lambda do |sources, parent_origin|
|
79
|
+
ReadHttpSources.call(sources, parent_origin).map do |source_promise|
|
80
|
+
source_promise.then do |s|
|
81
|
+
s = s.dup.force_encoding("UTF-8")
|
82
|
+
unless s.valid_encoding?
|
83
|
+
raise ImportFailedException, "#{s.inspect} is not valid UTF-8"
|
84
|
+
end
|
85
|
+
s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
66
90
|
RejectSources = lambda do |sources|
|
67
91
|
sources.map do |source|
|
68
92
|
Promise.new.reject(ImportBannedException.new(source))
|
@@ -74,7 +98,7 @@ module Dhall
|
|
74
98
|
path_reader: ReadPathSources,
|
75
99
|
http_reader: ReadHttpSources,
|
76
100
|
https_reader: http_reader,
|
77
|
-
public_gateway: "cloudflare-ipfs.com"
|
101
|
+
public_gateway: URI("https://cloudflare-ipfs.com")
|
78
102
|
)
|
79
103
|
@path_reader = path_reader
|
80
104
|
@http_reader = http_reader
|
@@ -89,7 +113,7 @@ module Dhall
|
|
89
113
|
def call(sources)
|
90
114
|
@path_reader.call(sources).map.with_index do |promise, idx|
|
91
115
|
source = sources[idx]
|
92
|
-
if source.is_a?(Import::AbsolutePath) &&
|
116
|
+
if source.canonical.is_a?(Import::AbsolutePath) &&
|
93
117
|
["ipfs", "ipns"].include?(source.path.first)
|
94
118
|
gateway_fallback(source, promise)
|
95
119
|
else
|
@@ -107,7 +131,7 @@ module Dhall
|
|
107
131
|
def gateway_fallback(source, promise)
|
108
132
|
promise.catch {
|
109
133
|
@http_reader.call([
|
110
|
-
source.to_uri(Import::Http, "localhost:8000")
|
134
|
+
source.to_uri(Import::Http, URI("http://localhost:8000"))
|
111
135
|
], "localhost").first
|
112
136
|
}.catch do
|
113
137
|
@https_reader.call([
|
@@ -117,17 +141,67 @@ module Dhall
|
|
117
141
|
end
|
118
142
|
end
|
119
143
|
|
144
|
+
module NoCache
|
145
|
+
def self.fetch(*)
|
146
|
+
yield
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class RamCache
|
151
|
+
def initialize
|
152
|
+
@cache = {}
|
153
|
+
end
|
154
|
+
|
155
|
+
def fetch(key, &block)
|
156
|
+
return @cache[key] if @cache.key?(key)
|
157
|
+
|
158
|
+
Promise.resolve(nil).then(&block).then do |result|
|
159
|
+
@cache[key] = result
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class StandardFileCache
|
165
|
+
def initialize(
|
166
|
+
dir=Pathname.new(ENV.fetch(
|
167
|
+
"XDG_CACHE_HOME", ENV.fetch("HOME") + "/.cache/"
|
168
|
+
)) + "dhall/"
|
169
|
+
)
|
170
|
+
dir.mkpath
|
171
|
+
@dir = dir
|
172
|
+
@ram = RamCache.new
|
173
|
+
end
|
174
|
+
|
175
|
+
def fetch(key, &block)
|
176
|
+
if key.is_a?(String) && key.start_with?("sha256:")
|
177
|
+
file = @dir + key.sub(/^sha256:/, "1220")
|
178
|
+
return Dhall.from_binary(file.binread) if file.exist?
|
179
|
+
|
180
|
+
Promise.resolve(nil).then(&block).then do |result|
|
181
|
+
file.open("wb") { |fh| fh.write(result.to_cbor) }
|
182
|
+
result
|
183
|
+
end
|
184
|
+
else
|
185
|
+
@ram.fetch(key, &block)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
120
190
|
class ResolutionSet
|
121
|
-
def initialize(reader)
|
191
|
+
def initialize(reader, max_depth:)
|
122
192
|
@reader = reader
|
193
|
+
@max_depth = max_depth
|
123
194
|
@parents = []
|
124
195
|
@set = Hash.new { |h, k| h[k] = [] }
|
125
196
|
end
|
126
197
|
|
127
198
|
def register(source)
|
128
199
|
p = Promise.new
|
129
|
-
if @parents.include?(source)
|
200
|
+
if @parents.include?(source.canonical)
|
130
201
|
p.reject(ImportLoopException.new(source))
|
202
|
+
elsif @parents.length + 1 > @max_depth
|
203
|
+
msg = "Max import depth of #{@max_depth} exceeded"
|
204
|
+
p.reject(ImportFailedException.new(msg))
|
131
205
|
else
|
132
206
|
@set[source] << p
|
133
207
|
end
|
@@ -141,6 +215,8 @@ module Dhall
|
|
141
215
|
|
142
216
|
def reader
|
143
217
|
lambda do |sources|
|
218
|
+
raise TimeoutException if sources.any? { |s| s.deadline.exceeded? }
|
219
|
+
|
144
220
|
if @reader.arity == 2
|
145
221
|
@reader.call(sources, @parents.last&.origin || "localhost")
|
146
222
|
else
|
@@ -159,28 +235,66 @@ module Dhall
|
|
159
235
|
end
|
160
236
|
end
|
161
237
|
|
238
|
+
class SourceWithDeadline < SimpleDelegator
|
239
|
+
attr_reader :deadline
|
240
|
+
|
241
|
+
def initialize(source, deadline)
|
242
|
+
@source = source
|
243
|
+
@deadline = deadline
|
244
|
+
|
245
|
+
super(source)
|
246
|
+
end
|
247
|
+
|
248
|
+
def to_uri(*args)
|
249
|
+
self.class.new(super, deadline)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
162
253
|
class Standard
|
254
|
+
attr_reader :deadline
|
255
|
+
|
163
256
|
def initialize(
|
164
257
|
path_reader: ReadPathSources,
|
165
|
-
http_reader:
|
166
|
-
https_reader: http_reader
|
258
|
+
http_reader: StandardReadHttpSources,
|
259
|
+
https_reader: http_reader,
|
260
|
+
environment_reader: ReadEnvironmentSources,
|
261
|
+
cache: StandardFileCache.new,
|
262
|
+
max_depth: Float::INFINITY
|
167
263
|
)
|
168
|
-
@path_resolutions = ResolutionSet.new(path_reader)
|
169
|
-
@http_resolutions = ResolutionSet.new(http_reader)
|
170
|
-
@https_resolutions = ResolutionSet.new(https_reader)
|
171
|
-
@
|
264
|
+
@path_resolutions = ResolutionSet.new(path_reader, max_depth: max_depth)
|
265
|
+
@http_resolutions = ResolutionSet.new(http_reader, max_depth: max_depth)
|
266
|
+
@https_resolutions = ResolutionSet.new(https_reader, max_depth: max_depth)
|
267
|
+
@env_resolutions = ResolutionSet.new(
|
268
|
+
environment_reader, max_depth: max_depth
|
269
|
+
)
|
270
|
+
@deadline = Util::NoDeadline.new
|
271
|
+
@cache = cache
|
272
|
+
end
|
273
|
+
|
274
|
+
def with_deadline(deadline)
|
275
|
+
dup.tap do |c|
|
276
|
+
c.instance_eval do
|
277
|
+
@deadline = deadline
|
278
|
+
end
|
279
|
+
end
|
172
280
|
end
|
173
281
|
|
174
282
|
def cache_fetch(key, &fallback)
|
175
283
|
@cache.fetch(key) do
|
176
|
-
Promise.resolve(nil).then(&fallback)
|
177
|
-
@cache[key] = result
|
178
|
-
end
|
284
|
+
Promise.resolve(nil).then(&fallback)
|
179
285
|
end
|
180
286
|
end
|
181
287
|
|
182
288
|
def resolve_path(path_source)
|
183
|
-
@path_resolutions.register(
|
289
|
+
@path_resolutions.register(
|
290
|
+
SourceWithDeadline.new(path_source, @deadline)
|
291
|
+
)
|
292
|
+
end
|
293
|
+
|
294
|
+
def resolve_environment(env_source)
|
295
|
+
@env_resolutions.register(
|
296
|
+
SourceWithDeadline.new(env_source, @deadline)
|
297
|
+
)
|
184
298
|
end
|
185
299
|
|
186
300
|
def resolve_http(http_source)
|
@@ -188,8 +302,9 @@ module Dhall
|
|
188
302
|
resolver: self,
|
189
303
|
relative_to: Dhall::Import::RelativePath.new
|
190
304
|
).then do |headers|
|
305
|
+
source = http_source.with(headers: headers.normalize)
|
191
306
|
@http_resolutions.register(
|
192
|
-
|
307
|
+
SourceWithDeadline.new(source, @deadline)
|
193
308
|
)
|
194
309
|
end
|
195
310
|
end
|
@@ -199,8 +314,9 @@ module Dhall
|
|
199
314
|
resolver: self,
|
200
315
|
relative_to: Dhall::Import::RelativePath.new
|
201
316
|
).then do |headers|
|
317
|
+
source = https_source.with(headers: headers.normalize)
|
202
318
|
@https_resolutions.register(
|
203
|
-
|
319
|
+
SourceWithDeadline.new(source, @deadline)
|
204
320
|
)
|
205
321
|
end
|
206
322
|
end
|
@@ -208,6 +324,7 @@ module Dhall
|
|
208
324
|
def finish!
|
209
325
|
[
|
210
326
|
@path_resolutions,
|
327
|
+
@env_resolutions,
|
211
328
|
@http_resolutions,
|
212
329
|
@https_resolutions
|
213
330
|
].each do |rset|
|
@@ -220,6 +337,7 @@ module Dhall
|
|
220
337
|
dup.tap do |c|
|
221
338
|
c.instance_eval do
|
222
339
|
@path_resolutions = @path_resolutions.child(parent_source)
|
340
|
+
@env_resolutions = @env_resolutions.child(parent_source)
|
223
341
|
@http_resolutions = @http_resolutions.child(parent_source)
|
224
342
|
@https_resolutions = @https_resolutions.child(parent_source)
|
225
343
|
end
|
@@ -232,27 +350,36 @@ module Dhall
|
|
232
350
|
path_reader: ReadPathSources,
|
233
351
|
http_reader: ReadHttpSources,
|
234
352
|
https_reader: http_reader,
|
235
|
-
|
353
|
+
environment_reader: ReadEnvironmentSources,
|
354
|
+
ipfs_public_gateway: URI("https://cloudflare-ipfs.com"),
|
355
|
+
cache: RamCache.new,
|
356
|
+
max_depth: 50
|
236
357
|
)
|
237
358
|
super(
|
238
|
-
path_reader:
|
359
|
+
path_reader: ReadPathAndIPFSSources.new(
|
239
360
|
path_reader: path_reader,
|
240
361
|
http_reader: http_reader,
|
241
362
|
https_reader: https_reader,
|
242
363
|
public_gateway: ipfs_public_gateway
|
243
364
|
),
|
244
|
-
http_reader:
|
245
|
-
|
365
|
+
http_reader: http_reader, https_reader: https_reader, cache: cache,
|
366
|
+
environment_reader: environment_reader, max_depth: max_depth
|
246
367
|
)
|
247
368
|
end
|
248
369
|
end
|
249
370
|
|
250
371
|
class LocalOnly < Standard
|
251
|
-
def initialize(
|
372
|
+
def initialize(
|
373
|
+
path_reader: ReadPathSources,
|
374
|
+
environment_reader: ReadEnvironmentSources,
|
375
|
+
max_depth: 50
|
376
|
+
)
|
252
377
|
super(
|
253
|
-
path_reader:
|
254
|
-
|
255
|
-
|
378
|
+
path_reader: path_reader,
|
379
|
+
environment_reader: environment_reader,
|
380
|
+
http_reader: RejectSources,
|
381
|
+
https_reader: RejectSources,
|
382
|
+
max_depth: max_depth
|
256
383
|
)
|
257
384
|
end
|
258
385
|
end
|
@@ -260,9 +387,10 @@ module Dhall
|
|
260
387
|
class None < Default
|
261
388
|
def initialize
|
262
389
|
super(
|
263
|
-
path_reader:
|
264
|
-
|
265
|
-
|
390
|
+
path_reader: RejectSources,
|
391
|
+
environment_reader: RejectSources,
|
392
|
+
http_reader: RejectSources,
|
393
|
+
https_reader: RejectSources
|
266
394
|
)
|
267
395
|
end
|
268
396
|
end
|
@@ -291,9 +419,25 @@ module Dhall
|
|
291
419
|
).then { |h| @expr.with(h) }
|
292
420
|
end
|
293
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
|
+
|
294
430
|
class ImportResolver < ExpressionResolver
|
295
431
|
register_for Import
|
296
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
|
+
|
297
441
|
def resolve(resolver:, relative_to:)
|
298
442
|
Promise.resolve(nil).then do
|
299
443
|
resolver.cache_fetch(@expr.cache_key(relative_to)) do
|
@@ -305,7 +449,9 @@ module Dhall
|
|
305
449
|
def resolve_raw(resolver:, relative_to:)
|
306
450
|
real_path = @expr.real_path(relative_to)
|
307
451
|
real_path.resolve(resolver).then do |result|
|
308
|
-
@expr.
|
452
|
+
@expr.parse_resolve_check(
|
453
|
+
result,
|
454
|
+
deadline: resolver.deadline,
|
309
455
|
resolver: resolver.child(real_path),
|
310
456
|
relative_to: real_path
|
311
457
|
)
|
@@ -316,9 +462,15 @@ module Dhall
|
|
316
462
|
class FallbackResolver < ExpressionResolver
|
317
463
|
register_for Operator::ImportFallback
|
318
464
|
|
319
|
-
def resolve(
|
320
|
-
ExpressionResolver.for(@expr.lhs).resolve(
|
321
|
-
|
465
|
+
def resolve(resolver:, relative_to:)
|
466
|
+
ExpressionResolver.for(@expr.lhs).resolve(
|
467
|
+
resolver: resolver,
|
468
|
+
relative_to: relative_to
|
469
|
+
).catch do
|
470
|
+
@expr.rhs.resolve(
|
471
|
+
resolver: resolver.child(Import::MissingImport.new),
|
472
|
+
relative_to: relative_to
|
473
|
+
)
|
322
474
|
end
|
323
475
|
end
|
324
476
|
end
|
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
|
@@ -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
|
|
@@ -40,9 +42,13 @@ module Dhall
|
|
40
42
|
@typecheckers[node_type] ||= [typechecker, extras]
|
41
43
|
end
|
42
44
|
|
43
|
-
def self.
|
45
|
+
def self.annotate(expr)
|
44
46
|
return if expr.nil?
|
45
|
-
TypeChecker.for(expr).annotate(TypeChecker::Context.new)
|
47
|
+
TypeChecker.for(expr).annotate(TypeChecker::Context.new)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.type_of(expr)
|
51
|
+
annotate(expr)&.type
|
46
52
|
end
|
47
53
|
|
48
54
|
class Context
|
@@ -72,9 +78,9 @@ module Dhall
|
|
72
78
|
end
|
73
79
|
|
74
80
|
KINDS = [
|
75
|
-
|
76
|
-
|
77
|
-
|
81
|
+
Builtins[:Type],
|
82
|
+
Builtins[:Kind],
|
83
|
+
Builtins[:Sort]
|
78
84
|
].freeze
|
79
85
|
|
80
86
|
class Variable
|
@@ -84,38 +90,12 @@ module Dhall
|
|
84
90
|
@var = var
|
85
91
|
end
|
86
92
|
|
87
|
-
BUILTIN = {
|
88
|
-
"Type" => Dhall::Variable["Kind"],
|
89
|
-
"Kind" => Dhall::Variable["Sort"],
|
90
|
-
"Bool" => Dhall::Variable["Type"],
|
91
|
-
"Natural" => Dhall::Variable["Type"],
|
92
|
-
"Integer" => Dhall::Variable["Type"],
|
93
|
-
"Double" => Dhall::Variable["Type"],
|
94
|
-
"Text" => Dhall::Variable["Type"],
|
95
|
-
"List" => Dhall::Forall.of_arguments(
|
96
|
-
Dhall::Variable["Type"],
|
97
|
-
body: Dhall::Variable["Type"]
|
98
|
-
),
|
99
|
-
"Optional" => Dhall::Forall.of_arguments(
|
100
|
-
Dhall::Variable["Type"],
|
101
|
-
body: Dhall::Variable["Type"]
|
102
|
-
),
|
103
|
-
"None" => Dhall::Forall.new(
|
104
|
-
var: "A",
|
105
|
-
type: Dhall::Variable["Type"],
|
106
|
-
body: Dhall::Application.new(
|
107
|
-
function: Dhall::Variable["Optional"],
|
108
|
-
argument: Dhall::Variable["A"]
|
109
|
-
)
|
110
|
-
)
|
111
|
-
}.freeze
|
112
|
-
|
113
93
|
def annotate(context)
|
114
94
|
raise TypeError, "Sort has no Type, Kind, or Sort" if @var.name == "Sort"
|
115
95
|
|
116
96
|
Dhall::TypeAnnotation.new(
|
117
97
|
value: @var,
|
118
|
-
type:
|
98
|
+
type: context.fetch(@var)
|
119
99
|
)
|
120
100
|
end
|
121
101
|
end
|
@@ -130,6 +110,7 @@ module Dhall
|
|
130
110
|
def initialize(lit)
|
131
111
|
@lit = lit
|
132
112
|
@type = Dhall::Variable[lit.class.name.split(/::/).last]
|
113
|
+
@type = Builtins[@type.name.to_sym] || @type
|
133
114
|
end
|
134
115
|
|
135
116
|
def annotate(*)
|
@@ -170,14 +151,14 @@ module Dhall
|
|
170
151
|
def annotate(context)
|
171
152
|
chunks = Chunks.new(@lit.chunks).map { |c|
|
172
153
|
TypeChecker.for(c).annotate(context).tap do |annotated|
|
173
|
-
TypeChecker.assert annotated.type,
|
154
|
+
TypeChecker.assert annotated.type, Builtins[:Text],
|
174
155
|
"Cannot interpolate #{annotated.type}"
|
175
156
|
end
|
176
157
|
}.to_a
|
177
158
|
|
178
159
|
Dhall::TypeAnnotation.new(
|
179
160
|
value: @lit.with(chunks: chunks),
|
180
|
-
type:
|
161
|
+
type: Builtins[:Text]
|
181
162
|
)
|
182
163
|
end
|
183
164
|
end
|
@@ -194,9 +175,9 @@ module Dhall
|
|
194
175
|
|
195
176
|
class AnnotatedIf
|
196
177
|
def initialize(expr, apred, athen, aelse, context:)
|
197
|
-
TypeChecker.assert apred.type,
|
178
|
+
TypeChecker.assert apred.type, Builtins[:Bool],
|
198
179
|
"If must have a predicate of type Bool"
|
199
|
-
TypeChecker.assert_type athen.type,
|
180
|
+
TypeChecker.assert_type athen.type, Builtins[:Type],
|
200
181
|
"If branches must have types of type Type",
|
201
182
|
context: context
|
202
183
|
TypeChecker.assert aelse.type, athen.type,
|
@@ -225,13 +206,13 @@ module Dhall
|
|
225
206
|
|
226
207
|
class Operator
|
227
208
|
{
|
228
|
-
Dhall::Operator::And =>
|
229
|
-
Dhall::Operator::Or =>
|
230
|
-
Dhall::Operator::Equal =>
|
231
|
-
Dhall::Operator::NotEqual =>
|
232
|
-
Dhall::Operator::Plus =>
|
233
|
-
Dhall::Operator::Times =>
|
234
|
-
Dhall::Operator::TextConcatenate =>
|
209
|
+
Dhall::Operator::And => Builtins[:Bool],
|
210
|
+
Dhall::Operator::Or => Builtins[:Bool],
|
211
|
+
Dhall::Operator::Equal => Builtins[:Bool],
|
212
|
+
Dhall::Operator::NotEqual => Builtins[:Bool],
|
213
|
+
Dhall::Operator::Plus => Builtins[:Natural],
|
214
|
+
Dhall::Operator::Times => Builtins[:Natural],
|
215
|
+
Dhall::Operator::TextConcatenate => Builtins[:Text]
|
235
216
|
}.each do |node_type, type|
|
236
217
|
TypeChecker.register self, node_type, type
|
237
218
|
end
|
@@ -258,6 +239,31 @@ module Dhall
|
|
258
239
|
end
|
259
240
|
end
|
260
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
|
+
|
261
267
|
class OperatorListConcatenate
|
262
268
|
TypeChecker.register self, Dhall::Operator::ListConcatenate
|
263
269
|
|
@@ -270,7 +276,7 @@ module Dhall
|
|
270
276
|
module IsList
|
271
277
|
def self.===(other)
|
272
278
|
other.is_a?(Dhall::Application) &&
|
273
|
-
other.function ==
|
279
|
+
other.function == Builtins[:List]
|
274
280
|
end
|
275
281
|
end
|
276
282
|
|
@@ -334,10 +340,6 @@ module Dhall
|
|
334
340
|
"RecursiveRecordMerge got",
|
335
341
|
context: context
|
336
342
|
|
337
|
-
TypeChecker.assert_types_match annotated_lhs.type, annotated_rhs.type,
|
338
|
-
"RecursiveRecordMerge got mixed kinds",
|
339
|
-
context: context
|
340
|
-
|
341
343
|
[annotated_lhs, annotated_rhs]
|
342
344
|
end
|
343
345
|
|
@@ -361,12 +363,6 @@ module Dhall
|
|
361
363
|
end
|
362
364
|
|
363
365
|
def annotate(context)
|
364
|
-
kind = TypeChecker.assert_types_match(
|
365
|
-
@expr.lhs, @expr.rhs,
|
366
|
-
"RecursiveRecordTypeMerge mixed kinds",
|
367
|
-
context: context
|
368
|
-
)
|
369
|
-
|
370
366
|
type = @expr.lhs.deep_merge_type(@expr.rhs)
|
371
367
|
|
372
368
|
TypeChecker.assert type, Dhall::RecordType,
|
@@ -375,7 +371,13 @@ module Dhall
|
|
375
371
|
# Annotate to sanity check
|
376
372
|
TypeChecker.for(type).annotate(context)
|
377
373
|
|
378
|
-
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]
|
379
381
|
end
|
380
382
|
end
|
381
383
|
|
@@ -383,11 +385,17 @@ module Dhall
|
|
383
385
|
TypeChecker.register self, Dhall::EmptyList
|
384
386
|
|
385
387
|
def initialize(expr)
|
386
|
-
@expr = expr
|
388
|
+
@expr = expr.with(type: expr.type.normalize)
|
387
389
|
end
|
388
390
|
|
389
391
|
def annotate(context)
|
390
|
-
TypeChecker.
|
392
|
+
TypeChecker.assert @expr.type, Dhall::Application,
|
393
|
+
"EmptyList unknown type #{@expr.type.inspect}"
|
394
|
+
|
395
|
+
TypeChecker.assert @expr.type.function, Builtins[:List],
|
396
|
+
"EmptyList unknown type #{@expr.type.inspect}"
|
397
|
+
|
398
|
+
TypeChecker.assert_type @expr.element_type, Builtins[:Type],
|
391
399
|
"EmptyList element type not of type Type",
|
392
400
|
context: context
|
393
401
|
|
@@ -408,16 +416,16 @@ module Dhall
|
|
408
416
|
end
|
409
417
|
|
410
418
|
def annotation
|
411
|
-
list = @alist.with(
|
419
|
+
list = @alist.with(type: Builtins[:List].call(element_type))
|
412
420
|
Dhall::TypeAnnotation.new(type: list.type, value: list)
|
413
421
|
end
|
414
422
|
|
415
423
|
def element_type
|
416
|
-
@alist.first.value&.type || @alist.element_type
|
424
|
+
(@alist.first.value&.type || @alist.element_type).normalize
|
417
425
|
end
|
418
426
|
|
419
427
|
def element_types
|
420
|
-
@alist.to_a.map(&:type)
|
428
|
+
@alist.to_a.map(&:type).map(&:normalize)
|
421
429
|
end
|
422
430
|
end
|
423
431
|
|
@@ -430,7 +438,7 @@ module Dhall
|
|
430
438
|
Util::ArrayOf.new(alist.element_type),
|
431
439
|
"Non-homogenous List"
|
432
440
|
|
433
|
-
TypeChecker.assert_type alist.element_type,
|
441
|
+
TypeChecker.assert_type alist.element_type, Builtins[:Type],
|
434
442
|
"List type not of type Type", context: context
|
435
443
|
|
436
444
|
alist.annotation
|
@@ -447,7 +455,7 @@ module Dhall
|
|
447
455
|
def annotate(context)
|
448
456
|
TypeChecker.assert(
|
449
457
|
TypeChecker.for(@expr.value_type).annotate(context).type,
|
450
|
-
|
458
|
+
Builtins[:Type],
|
451
459
|
"OptionalNone element type not of type Type"
|
452
460
|
)
|
453
461
|
|
@@ -469,7 +477,7 @@ module Dhall
|
|
469
477
|
some = asome.with(value_type: asome.value.type)
|
470
478
|
|
471
479
|
type_type = TypeChecker.for(some.value_type).annotate(context).type
|
472
|
-
TypeChecker.assert type_type,
|
480
|
+
TypeChecker.assert type_type, Builtins[:Type],
|
473
481
|
"Some type not of type Type, was: #{type_type}"
|
474
482
|
|
475
483
|
Dhall::TypeAnnotation.new(type: some.type, value: some)
|
@@ -486,20 +494,27 @@ module Dhall
|
|
486
494
|
def annotate(*)
|
487
495
|
Dhall::TypeAnnotation.new(
|
488
496
|
value: @expr,
|
489
|
-
type:
|
497
|
+
type: Builtins[:Type]
|
490
498
|
)
|
491
499
|
end
|
492
500
|
end
|
493
501
|
|
494
502
|
class AnonymousType
|
495
503
|
TypeChecker.register self, Dhall::RecordType
|
496
|
-
TypeChecker.register self, Dhall::UnionType
|
497
504
|
|
498
505
|
def initialize(type)
|
499
506
|
@type = type
|
500
507
|
end
|
501
508
|
|
502
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)
|
503
518
|
kinds = @type.record.values.compact.map do |mtype|
|
504
519
|
TypeChecker.for(mtype).annotate(context).type
|
505
520
|
end
|
@@ -507,6 +522,16 @@ module Dhall
|
|
507
522
|
TypeChecker.assert (kinds - KINDS), [],
|
508
523
|
"AnonymousType field kind not one of #{KINDS}"
|
509
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
|
+
|
510
535
|
TypeChecker.assert kinds, Util::ArrayAllTheSame,
|
511
536
|
"AnonymousType field kinds not all the same"
|
512
537
|
|
@@ -562,12 +587,13 @@ module Dhall
|
|
562
587
|
|
563
588
|
class Selector
|
564
589
|
def self.for(annotated_record)
|
565
|
-
|
590
|
+
typ = annotated_record.type.normalize
|
591
|
+
if KINDS.include?(typ)
|
566
592
|
TypeSelector.new(annotated_record.value)
|
567
|
-
elsif
|
568
|
-
new(
|
593
|
+
elsif typ.class == Dhall::RecordType
|
594
|
+
new(typ)
|
569
595
|
else
|
570
|
-
raise TypeError, "RecordSelection on #{
|
596
|
+
raise TypeError, "RecordSelection on #{typ}"
|
571
597
|
end
|
572
598
|
end
|
573
599
|
|
@@ -629,6 +655,52 @@ module Dhall
|
|
629
655
|
end
|
630
656
|
end
|
631
657
|
|
658
|
+
class RecordProjectionByExpression
|
659
|
+
TypeChecker.register self, Dhall::RecordProjectionByExpression
|
660
|
+
|
661
|
+
def initialize(projection)
|
662
|
+
@selector = projection.selector.normalize
|
663
|
+
@project_by_expression = projection
|
664
|
+
@project_by_keys = Dhall::RecordProjection.for(
|
665
|
+
@project_by_expression.record,
|
666
|
+
@selector.keys
|
667
|
+
)
|
668
|
+
end
|
669
|
+
|
670
|
+
def annotate(context)
|
671
|
+
TypeChecker.assert @selector, Dhall::RecordType,
|
672
|
+
"RecordProjectionByExpression on #{@selector.class}"
|
673
|
+
|
674
|
+
TypeChecker.assert_type @project_by_keys, @selector,
|
675
|
+
"Type doesn't match #{@selector}",
|
676
|
+
context: context
|
677
|
+
|
678
|
+
Dhall::TypeAnnotation.new(
|
679
|
+
value: @project_by_expression,
|
680
|
+
type: @selector
|
681
|
+
)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
class Enum
|
686
|
+
TypeChecker.register self, Dhall::Enum
|
687
|
+
|
688
|
+
def initialize(enum)
|
689
|
+
@enum = enum
|
690
|
+
end
|
691
|
+
|
692
|
+
def annotate(context)
|
693
|
+
type = Dhall::UnionType.new(
|
694
|
+
alternatives: { @enum.tag => nil }
|
695
|
+
).merge(@enum.alternatives)
|
696
|
+
|
697
|
+
# Annotate to sanity check
|
698
|
+
TypeChecker.for(type).annotate(context)
|
699
|
+
|
700
|
+
Dhall::TypeAnnotation.new(value: @enum, type: type)
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
632
704
|
class Union
|
633
705
|
TypeChecker.register self, Dhall::Union
|
634
706
|
|
@@ -654,6 +726,39 @@ module Dhall
|
|
654
726
|
end
|
655
727
|
end
|
656
728
|
|
729
|
+
class ToMap
|
730
|
+
TypeChecker.register self, Dhall::ToMap
|
731
|
+
|
732
|
+
def initialize(tomap)
|
733
|
+
@tomap = tomap
|
734
|
+
@record = TypeChecker.for(tomap.record)
|
735
|
+
end
|
736
|
+
|
737
|
+
def check_annotation(record_type)
|
738
|
+
if record_type.is_a?(Dhall::EmptyRecordType)
|
739
|
+
TypeChecker.assert @tomap.type, Dhall::Expression,
|
740
|
+
"toMap {=} has no annotation"
|
741
|
+
else
|
742
|
+
t = Types::MAP(v: record_type.record.values.first)
|
743
|
+
|
744
|
+
TypeChecker.assert t, (@tomap.type || t),
|
745
|
+
"toMap does not match annotation"
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
def annotate(context)
|
750
|
+
record_type = @record.annotate(context).type
|
751
|
+
TypeChecker.assert record_type, Dhall::RecordType,
|
752
|
+
"toMap on a non-record: #{record_type.inspect}"
|
753
|
+
|
754
|
+
TypeChecker.assert record_type.record.values, Util::ArrayAllTheSame,
|
755
|
+
"toMap heterogenous: #{record_type.inspect}"
|
756
|
+
|
757
|
+
type = check_annotation(record_type)
|
758
|
+
Dhall::TypeAnnotation.new(value: @tomap, type: type)
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
657
762
|
class Merge
|
658
763
|
TypeChecker.register self, Dhall::Merge
|
659
764
|
|
@@ -684,7 +789,7 @@ module Dhall
|
|
684
789
|
end
|
685
790
|
|
686
791
|
def keys
|
687
|
-
@type.record.keys
|
792
|
+
Set.new(@type.record.keys)
|
688
793
|
end
|
689
794
|
|
690
795
|
def fetch_input_type(k)
|
@@ -727,7 +832,7 @@ module Dhall
|
|
727
832
|
|
728
833
|
TypeChecker.assert(
|
729
834
|
kind,
|
730
|
-
|
835
|
+
Builtins[:Type],
|
731
836
|
"Merge must have kind Type"
|
732
837
|
)
|
733
838
|
|
@@ -735,8 +840,8 @@ module Dhall
|
|
735
840
|
end
|
736
841
|
|
737
842
|
def assert_union_and_handlers_match
|
738
|
-
extras = @handlers.keys
|
739
|
-
TypeChecker.assert extras, [],
|
843
|
+
extras = @handlers.keys ^ @union.type.alternatives.keys
|
844
|
+
TypeChecker.assert extras.to_a, [],
|
740
845
|
"Merge handlers unknown alternatives: #{extras}"
|
741
846
|
|
742
847
|
@union.type.alternatives.each do |k, atype|
|
@@ -777,8 +882,6 @@ module Dhall
|
|
777
882
|
raise TypeError, "FunctionType part of this is a term"
|
778
883
|
end
|
779
884
|
|
780
|
-
raise TypeError, "Dependent types are not allowed" if outkind > inkind
|
781
|
-
|
782
885
|
if outkind.zero?
|
783
886
|
Term.new
|
784
887
|
else
|
@@ -866,8 +969,6 @@ module Dhall
|
|
866
969
|
end
|
867
970
|
end
|
868
971
|
|
869
|
-
TypeChecker.register ->(blk) { LetIn.for(blk.unflatten) }, Dhall::LetBlock
|
870
|
-
|
871
972
|
class LetIn
|
872
973
|
TypeChecker.register self, Dhall::LetIn
|
873
974
|
|
@@ -933,11 +1034,58 @@ module Dhall
|
|
933
1034
|
end
|
934
1035
|
end
|
935
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
|
+
|
936
1061
|
BUILTIN_TYPES = {
|
1062
|
+
"Bool" => Builtins[:Type],
|
1063
|
+
"Type" => Builtins[:Kind],
|
1064
|
+
"Kind" => Builtins[:Sort],
|
1065
|
+
"Natural" => Builtins[:Type],
|
1066
|
+
"Integer" => Builtins[:Type],
|
1067
|
+
"Double" => Builtins[:Type],
|
1068
|
+
"Text" => Builtins[:Type],
|
1069
|
+
"List" => Dhall::Forall.of_arguments(
|
1070
|
+
Builtins[:Type],
|
1071
|
+
body: Builtins[:Type]
|
1072
|
+
),
|
1073
|
+
"Optional" => Dhall::Forall.of_arguments(
|
1074
|
+
Builtins[:Type],
|
1075
|
+
body: Builtins[:Type]
|
1076
|
+
),
|
1077
|
+
"None" => Dhall::Forall.new(
|
1078
|
+
var: "A",
|
1079
|
+
type: Builtins[:Type],
|
1080
|
+
body: Dhall::Application.new(
|
1081
|
+
function: Builtins[:Optional],
|
1082
|
+
argument: Dhall::Variable["A"]
|
1083
|
+
)
|
1084
|
+
),
|
937
1085
|
"Natural/build" => Dhall::Forall.of_arguments(
|
938
1086
|
Dhall::Forall.new(
|
939
1087
|
var: "natural",
|
940
|
-
type:
|
1088
|
+
type: Builtins[:Type],
|
941
1089
|
body: Dhall::Forall.new(
|
942
1090
|
var: "succ",
|
943
1091
|
type: Dhall::Forall.of_arguments(
|
@@ -951,13 +1099,13 @@ module Dhall
|
|
951
1099
|
)
|
952
1100
|
)
|
953
1101
|
),
|
954
|
-
body:
|
1102
|
+
body: Builtins[:Natural]
|
955
1103
|
),
|
956
1104
|
"Natural/fold" => Dhall::Forall.of_arguments(
|
957
|
-
|
1105
|
+
Builtins[:Natural],
|
958
1106
|
body: Dhall::Forall.new(
|
959
1107
|
var: "natural",
|
960
|
-
type:
|
1108
|
+
type: Builtins[:Type],
|
961
1109
|
body: Dhall::Forall.new(
|
962
1110
|
var: "succ",
|
963
1111
|
type: Dhall::Forall.of_arguments(
|
@@ -972,37 +1120,42 @@ module Dhall
|
|
972
1120
|
)
|
973
1121
|
)
|
974
1122
|
),
|
1123
|
+
"Natural/subtract" => Dhall::Forall.of_arguments(
|
1124
|
+
Builtins[:Natural],
|
1125
|
+
Builtins[:Natural],
|
1126
|
+
body: Builtins[:Natural]
|
1127
|
+
),
|
975
1128
|
"Natural/isZero" => Dhall::Forall.of_arguments(
|
976
|
-
|
977
|
-
body:
|
1129
|
+
Builtins[:Natural],
|
1130
|
+
body: Builtins[:Bool]
|
978
1131
|
),
|
979
1132
|
"Natural/even" => Dhall::Forall.of_arguments(
|
980
|
-
|
981
|
-
body:
|
1133
|
+
Builtins[:Natural],
|
1134
|
+
body: Builtins[:Bool]
|
982
1135
|
),
|
983
1136
|
"Natural/odd" => Dhall::Forall.of_arguments(
|
984
|
-
|
985
|
-
body:
|
1137
|
+
Builtins[:Natural],
|
1138
|
+
body: Builtins[:Bool]
|
986
1139
|
),
|
987
1140
|
"Natural/toInteger" => Dhall::Forall.of_arguments(
|
988
|
-
|
989
|
-
body:
|
1141
|
+
Builtins[:Natural],
|
1142
|
+
body: Builtins[:Integer]
|
990
1143
|
),
|
991
1144
|
"Natural/show" => Dhall::Forall.of_arguments(
|
992
|
-
|
993
|
-
body:
|
1145
|
+
Builtins[:Natural],
|
1146
|
+
body: Builtins[:Text]
|
994
1147
|
),
|
995
1148
|
"Text/show" => Dhall::Forall.of_arguments(
|
996
|
-
|
997
|
-
body:
|
1149
|
+
Builtins[:Text],
|
1150
|
+
body: Builtins[:Text]
|
998
1151
|
),
|
999
1152
|
"List/build" => Dhall::Forall.new(
|
1000
1153
|
var: "a",
|
1001
|
-
type:
|
1154
|
+
type: Builtins[:Type],
|
1002
1155
|
body: Dhall::Forall.of_arguments(
|
1003
1156
|
Dhall::Forall.new(
|
1004
1157
|
var: "list",
|
1005
|
-
type:
|
1158
|
+
type: Builtins[:Type],
|
1006
1159
|
body: Dhall::Forall.new(
|
1007
1160
|
var: "cons",
|
1008
1161
|
type: Dhall::Forall.of_arguments(
|
@@ -1018,22 +1171,22 @@ module Dhall
|
|
1018
1171
|
)
|
1019
1172
|
),
|
1020
1173
|
body: Dhall::Application.new(
|
1021
|
-
function:
|
1174
|
+
function: Builtins[:List],
|
1022
1175
|
argument: Dhall::Variable["a"]
|
1023
1176
|
)
|
1024
1177
|
)
|
1025
1178
|
),
|
1026
1179
|
"List/fold" => Dhall::Forall.new(
|
1027
1180
|
var: "a",
|
1028
|
-
type:
|
1181
|
+
type: Builtins[:Type],
|
1029
1182
|
body: Dhall::Forall.of_arguments(
|
1030
1183
|
Dhall::Application.new(
|
1031
|
-
function:
|
1184
|
+
function: Builtins[:List],
|
1032
1185
|
argument: Dhall::Variable["a"]
|
1033
1186
|
),
|
1034
1187
|
body: Dhall::Forall.new(
|
1035
1188
|
var: "list",
|
1036
|
-
type:
|
1189
|
+
type: Builtins[:Type],
|
1037
1190
|
body: Dhall::Forall.new(
|
1038
1191
|
var: "cons",
|
1039
1192
|
type: Dhall::Forall.of_arguments(
|
@@ -1052,56 +1205,56 @@ module Dhall
|
|
1052
1205
|
),
|
1053
1206
|
"List/length" => Dhall::Forall.new(
|
1054
1207
|
var: "a",
|
1055
|
-
type:
|
1208
|
+
type: Builtins[:Type],
|
1056
1209
|
body: Dhall::Forall.of_arguments(
|
1057
1210
|
Dhall::Application.new(
|
1058
|
-
function:
|
1211
|
+
function: Builtins[:List],
|
1059
1212
|
argument: Dhall::Variable["a"]
|
1060
1213
|
),
|
1061
|
-
body:
|
1214
|
+
body: Builtins[:Natural]
|
1062
1215
|
)
|
1063
1216
|
),
|
1064
1217
|
"List/head" => Dhall::Forall.new(
|
1065
1218
|
var: "a",
|
1066
|
-
type:
|
1219
|
+
type: Builtins[:Type],
|
1067
1220
|
body: Dhall::Forall.of_arguments(
|
1068
1221
|
Dhall::Application.new(
|
1069
|
-
function:
|
1222
|
+
function: Builtins[:List],
|
1070
1223
|
argument: Dhall::Variable["a"]
|
1071
1224
|
),
|
1072
1225
|
body: Dhall::Application.new(
|
1073
|
-
function:
|
1226
|
+
function: Builtins[:Optional],
|
1074
1227
|
argument: Dhall::Variable["a"]
|
1075
1228
|
)
|
1076
1229
|
)
|
1077
1230
|
),
|
1078
1231
|
"List/last" => Dhall::Forall.new(
|
1079
1232
|
var: "a",
|
1080
|
-
type:
|
1233
|
+
type: Builtins[:Type],
|
1081
1234
|
body: Dhall::Forall.of_arguments(
|
1082
1235
|
Dhall::Application.new(
|
1083
|
-
function:
|
1236
|
+
function: Builtins[:List],
|
1084
1237
|
argument: Dhall::Variable["a"]
|
1085
1238
|
),
|
1086
1239
|
body: Dhall::Application.new(
|
1087
|
-
function:
|
1240
|
+
function: Builtins[:Optional],
|
1088
1241
|
argument: Dhall::Variable["a"]
|
1089
1242
|
)
|
1090
1243
|
)
|
1091
1244
|
),
|
1092
1245
|
"List/indexed" => Dhall::Forall.new(
|
1093
1246
|
var: "a",
|
1094
|
-
type:
|
1247
|
+
type: Builtins[:Type],
|
1095
1248
|
body: Dhall::Forall.of_arguments(
|
1096
1249
|
Dhall::Application.new(
|
1097
|
-
function:
|
1250
|
+
function: Builtins[:List],
|
1098
1251
|
argument: Dhall::Variable["a"]
|
1099
1252
|
),
|
1100
1253
|
body: Dhall::Application.new(
|
1101
|
-
function:
|
1254
|
+
function: Builtins[:List],
|
1102
1255
|
argument: Dhall::RecordType.new(
|
1103
1256
|
record: {
|
1104
|
-
"index" =>
|
1257
|
+
"index" => Builtins[:Natural],
|
1105
1258
|
"value" => Dhall::Variable["a"]
|
1106
1259
|
}
|
1107
1260
|
)
|
@@ -1110,29 +1263,29 @@ module Dhall
|
|
1110
1263
|
),
|
1111
1264
|
"List/reverse" => Dhall::Forall.new(
|
1112
1265
|
var: "a",
|
1113
|
-
type:
|
1266
|
+
type: Builtins[:Type],
|
1114
1267
|
body: Dhall::Forall.of_arguments(
|
1115
1268
|
Dhall::Application.new(
|
1116
|
-
function:
|
1269
|
+
function: Builtins[:List],
|
1117
1270
|
argument: Dhall::Variable["a"]
|
1118
1271
|
),
|
1119
1272
|
body: Dhall::Application.new(
|
1120
|
-
function:
|
1273
|
+
function: Builtins[:List],
|
1121
1274
|
argument: Dhall::Variable["a"]
|
1122
1275
|
)
|
1123
1276
|
)
|
1124
1277
|
),
|
1125
1278
|
"Optional/fold" => Dhall::Forall.new(
|
1126
1279
|
var: "a",
|
1127
|
-
type:
|
1280
|
+
type: Builtins[:Type],
|
1128
1281
|
body: Dhall::Forall.of_arguments(
|
1129
1282
|
Dhall::Application.new(
|
1130
|
-
function:
|
1283
|
+
function: Builtins[:Optional],
|
1131
1284
|
argument: Dhall::Variable["a"]
|
1132
1285
|
),
|
1133
1286
|
body: Dhall::Forall.new(
|
1134
1287
|
var: "optional",
|
1135
|
-
type:
|
1288
|
+
type: Builtins[:Type],
|
1136
1289
|
body: Dhall::Forall.new(
|
1137
1290
|
var: "just",
|
1138
1291
|
type: Dhall::Forall.of_arguments(
|
@@ -1150,11 +1303,11 @@ module Dhall
|
|
1150
1303
|
),
|
1151
1304
|
"Optional/build" => Dhall::Forall.new(
|
1152
1305
|
var: "a",
|
1153
|
-
type:
|
1306
|
+
type: Builtins[:Type],
|
1154
1307
|
body: Dhall::Forall.of_arguments(
|
1155
1308
|
Dhall::Forall.new(
|
1156
1309
|
var: "optional",
|
1157
|
-
type:
|
1310
|
+
type: Builtins[:Type],
|
1158
1311
|
body: Dhall::Forall.new(
|
1159
1312
|
var: "just",
|
1160
1313
|
type: Dhall::Forall.of_arguments(
|
@@ -1169,28 +1322,38 @@ module Dhall
|
|
1169
1322
|
)
|
1170
1323
|
),
|
1171
1324
|
body: Dhall::Application.new(
|
1172
|
-
function:
|
1325
|
+
function: Builtins[:Optional],
|
1173
1326
|
argument: Dhall::Variable["a"]
|
1174
1327
|
)
|
1175
1328
|
)
|
1176
1329
|
),
|
1177
1330
|
"Integer/show" => Dhall::Forall.of_arguments(
|
1178
|
-
|
1179
|
-
body:
|
1331
|
+
Builtins[:Integer],
|
1332
|
+
body: Builtins[:Text]
|
1180
1333
|
),
|
1181
1334
|
"Integer/toDouble" => Dhall::Forall.of_arguments(
|
1182
|
-
|
1183
|
-
body:
|
1335
|
+
Builtins[:Integer],
|
1336
|
+
body: Builtins[:Double]
|
1184
1337
|
),
|
1185
1338
|
"Double/show" => Dhall::Forall.of_arguments(
|
1186
|
-
|
1187
|
-
body:
|
1339
|
+
Builtins[:Double],
|
1340
|
+
body: Builtins[:Text]
|
1188
1341
|
)
|
1189
1342
|
}.freeze
|
1190
1343
|
|
1191
1344
|
class Builtin
|
1192
1345
|
TypeChecker.register self, Dhall::Builtin
|
1193
1346
|
|
1347
|
+
def self.for(builtin)
|
1348
|
+
if builtin.is_a?(Dhall::BuiltinFunction)
|
1349
|
+
if (unfilled = builtin.unfill) != builtin
|
1350
|
+
return TypeChecker.for(unfilled)
|
1351
|
+
end
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
new(builtin)
|
1355
|
+
end
|
1356
|
+
|
1194
1357
|
def initialize(builtin)
|
1195
1358
|
@expr = builtin
|
1196
1359
|
@name = builtin.as_json
|