dhall 0.3.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 30ff6e0ad066b23996b9a31b21e7f1a30b86b265
4
- data.tar.gz: 88efb36ee05894a74df3b691d67774b8e0eea185
2
+ SHA256:
3
+ metadata.gz: c6ba874fec536af3a57ea4a0ca59f040076ebc03ed639dcd44a5a2b79e8bf252
4
+ data.tar.gz: 4408343df3c63a8c96f6e191f3109a2110ae4b6f3ab06aee58c15b2e7439f6ef
5
5
  SHA512:
6
- metadata.gz: ff197049f1d4ceb3e1742a4e3b44491192170c4bb1e32b7aef6bbaeb643f16b828ffdee1d78eaa628a9f0dd9d5dedd0f4c796556b2e72b92ed0705a0e8306430
7
- data.tar.gz: e92aad6b3921f4bd25ebdf8f20204b95ceec8814250ed90b5424b70a75991ca68de8bd60b0c2cf982541c560f9e1ba135f87f0b05f685d767588150b051c465f
6
+ metadata.gz: e3fdb1ed15e039261aedfc608d612eb4739b7a0204aa26524d66e8999d14ed71cc4e2b5964077f88cf860a99454548c7c2aae2188de9a9687fb173e780441fe4
7
+ data.tar.gz: 0b9b101c0ccaec5d6be7bbfab0a3698c1eb81f91c06ba9efe663391ce56e8e71613fb0f4cd37af12cc68e7973278fcd9f47190d80a0369c14230a3e0480cdda1
data/bin/dhall-compile CHANGED
@@ -13,19 +13,43 @@ def compile(source)
13
13
  resolver: Dhall::Resolvers::Default.new(
14
14
  max_depth: Float::INFINITY
15
15
  )
16
- ).then(&:to_binary)
16
+ )
17
+ end
18
+
19
+ module FilenameWriter
20
+ def self.write(_, out, dhall)
21
+ warn out
22
+ out.dirname.mkpath
23
+ out.write(dhall.to_binary)
24
+ end
25
+ end
26
+
27
+ module CacheWriter
28
+ def self.write(output_directory, out, dhall)
29
+ base = "1220#{dhall.digest.hexdigest}"
30
+ out = out.dirname + base
31
+ if output_directory
32
+ out = output_directory + base
33
+ out.dirname.mkpath
34
+ end
35
+ warn out
36
+ out.write(dhall.to_cbor)
37
+ end
17
38
  end
18
39
 
19
40
  def compile_file(file_path, relative_to: Pathname.new("."))
41
+ $stderr.print "#{file_path} => "
20
42
  out = file_path.sub_ext(@extension)
21
43
  if @output_directory
22
44
  out = @output_directory + out.relative_path_from(relative_to)
23
- out.dirname.mkpath
24
45
  end
25
- warn "#{file_path} => #{out}"
26
- compile(file_path.expand_path).then(&out.method(:write))
46
+ compile(file_path.expand_path).then do |dhall|
47
+ @writer.write(@output_directory, out, dhall)
48
+ end
27
49
  end
28
50
 
51
+ @writer = FilenameWriter
52
+ # rubocop:disable Metrics/BlockLength
29
53
  opt_parser = OptionParser.new do |opts|
30
54
  opts.banner = "Usage: dhall-compile [options] [-] [files_and_dirs]"
31
55
 
@@ -45,11 +69,21 @@ opt_parser = OptionParser.new do |opts|
45
69
  @extension = ext ? ".#{ext}" : ""
46
70
  end
47
71
 
72
+ opts.on(
73
+ "-c",
74
+ "--cache",
75
+ "Write output in standard dhall file cache format"
76
+ ) do
77
+ @extension = ""
78
+ @writer = CacheWriter
79
+ end
80
+
48
81
  opts.on("-h", "--help", "Show this usage information") do
49
82
  warn opts
50
83
  exit
51
84
  end
52
85
  end
86
+ # rubocop:enable Metrics/BlockLength
53
87
 
54
88
  opt_parser.parse!
55
89
 
data/bin/json-to-dhall CHANGED
@@ -5,4 +5,4 @@ require "dhall"
5
5
  require "json"
6
6
  using Dhall::AsDhall
7
7
 
8
- STDOUT.write(CBOR.encode(JSON.parse(STDIN.read).as_dhall))
8
+ STDOUT.write(JSON.parse(STDIN.read).as_dhall.to_binary)
data/bin/yaml-to-dhall CHANGED
@@ -5,4 +5,4 @@ require "dhall"
5
5
  require "yaml"
6
6
  using Dhall::AsDhall
7
7
 
8
- STDOUT.write(CBOR.encode(YAML.safe_load(STDIN.read, [Symbol]).as_dhall))
8
+ STDOUT.write(YAML.safe_load(STDIN.read, [Symbol]).as_dhall.to_binary)
data/dhall.gemspec CHANGED
@@ -25,12 +25,16 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
 
28
+ spec.add_dependency "base32", "~> 0.3.2"
28
29
  spec.add_dependency "cbor", "~> 0.5.9.3"
29
30
  spec.add_dependency "citrus", "~> 3.0"
31
+ spec.add_dependency "lazy_object", "~> 0.0.3"
32
+ spec.add_dependency "multihashes", "~> 0.2.0"
30
33
  spec.add_dependency "promise.rb", "~> 0.7.4"
31
34
  spec.add_dependency "value_semantics", "~> 3.0"
32
35
 
33
36
  spec.add_development_dependency "abnf", "~> 0.0.1"
37
+ spec.add_development_dependency "minitest-fail-fast", "~> 0.1.0"
34
38
  spec.add_development_dependency "simplecov", "~> 0.16.1"
35
39
  spec.add_development_dependency "webmock", "~> 3.5"
36
40
  end
@@ -284,5 +284,11 @@ module Dhall
284
284
  FunctionProxy.new(self)
285
285
  end
286
286
  end
287
+
288
+ refine ::Method do
289
+ def as_dhall
290
+ to_proc.as_dhall
291
+ end
292
+ end
287
293
  end
288
294
  end
data/lib/dhall/ast.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "base32"
4
+ require "lazy_object"
5
+ require "multihashes"
3
6
  require "uri"
4
7
  require "value_semantics"
5
8
 
@@ -33,8 +36,7 @@ module Dhall
33
36
  end
34
37
 
35
38
  def *(other)
36
- case other
37
- when Natural
39
+ if other.is_a?(Natural) && other.zero?
38
40
  other * self
39
41
  else
40
42
  Operator::Times.new(lhs: self, rhs: other)
@@ -68,7 +70,7 @@ module Dhall
68
70
  def dhall_eq(other)
69
71
  if self == other
70
72
  Bool.new(value: true)
71
- elsif other.is_a?(Bool)
73
+ elsif other == Bool.new(value: true)
72
74
  other.dhall_eq(self)
73
75
  else
74
76
  Operator::Equal.new(lhs: self, rhs: other)
@@ -102,6 +104,10 @@ module Dhall
102
104
  end
103
105
  end
104
106
 
107
+ def annotate(type)
108
+ TypeAnnotation.new(value: self, type: type)
109
+ end
110
+
105
111
  def to_s
106
112
  inspect
107
113
  end
@@ -128,7 +134,7 @@ module Dhall
128
134
  def flatten
129
135
  f, args = if function.is_a?(Application)
130
136
  function.flatten
131
- elsif function.is_a?(Builtin) &&
137
+ elsif function.is_a?(BuiltinFunction) &&
132
138
  (unfilled = function.unfill).is_a?(Application)
133
139
  unfilled.flatten
134
140
  else
@@ -216,7 +222,29 @@ module Dhall
216
222
  end
217
223
  end
218
224
 
219
- class FunctionProxy < Function
225
+ class RubyObjectRaw < Expression
226
+ def initialize(object)
227
+ @object = object
228
+ end
229
+
230
+ def unwrap
231
+ @object
232
+ end
233
+
234
+ def respond_to_missing?(m)
235
+ super || @object.respond_to?(m)
236
+ end
237
+
238
+ def method_missing(m, *args, &block)
239
+ if @object.respond_to?(m)
240
+ @object.public_send(m, *args, &block)
241
+ else
242
+ super
243
+ end
244
+ end
245
+ end
246
+
247
+ class FunctionProxyRaw < Function
220
248
  def initialize(callable, curry: true)
221
249
  @callable = if !curry
222
250
  callable
@@ -230,7 +258,7 @@ module Dhall
230
258
  end
231
259
 
232
260
  def call(*args, &block)
233
- @callable.call(*args.map { |arg| arg&.as_dhall }, &block).as_dhall
261
+ RubyObjectRaw.new(@callable.call(*args.map { |arg| arg&.as_dhall }, &block))
234
262
  end
235
263
 
236
264
  def as_json
@@ -238,6 +266,12 @@ module Dhall
238
266
  end
239
267
  end
240
268
 
269
+ class FunctionProxy < FunctionProxyRaw
270
+ def call(*args, &block)
271
+ super.unwrap.as_dhall
272
+ end
273
+ end
274
+
241
275
  class Bool < Expression
242
276
  include(ValueSemantics.for_attributes do
243
277
  value Bool()
@@ -317,6 +351,33 @@ module Dhall
317
351
  [3, OPERATORS.index(self.class), lhs.as_json, rhs.as_json]
318
352
  end
319
353
 
354
+ module FetchFromMerge
355
+ def fetch_second_record(first, second, selector)
356
+ rec = self.class.new(
357
+ self.class::FETCH2K => second.slice(selector),
358
+ self.class::FETCH1K => first
359
+ ).normalize
360
+
361
+ if rec.class == self.class
362
+ RecordSelection.new(record: rec, selector: selector)
363
+ else
364
+ rec.fetch(selector)
365
+ end
366
+ end
367
+
368
+ def fetch(selector)
369
+ first = public_send(self.class::FETCH1K)
370
+ second = public_send(self.class::FETCH2K)
371
+ if first.is_a?(Record)
372
+ first.fetch(selector) { second.fetch(selector) }
373
+ elsif second.is_a?(Record)
374
+ fetch_second_record(first, second, selector)
375
+ else
376
+ super
377
+ end
378
+ end
379
+ end
380
+
320
381
  class Or < Operator; end
321
382
  class And < Operator; end
322
383
  class Equal < Operator; end
@@ -325,17 +386,27 @@ module Dhall
325
386
  class Times < Operator; end
326
387
  class TextConcatenate < Operator; end
327
388
  class ListConcatenate < Operator; end
328
- class RecursiveRecordMerge < Operator; end
329
- class RightBiasedRecordMerge < Operator; end
389
+ class RecursiveRecordMerge < Operator
390
+ FETCH1K = :lhs
391
+ FETCH2K = :rhs
392
+ include FetchFromMerge
393
+ end
394
+ class RightBiasedRecordMerge < Operator
395
+ FETCH1K = :rhs
396
+ FETCH2K = :lhs
397
+ include FetchFromMerge
398
+ end
330
399
  class RecursiveRecordTypeMerge < Operator; end
331
400
  class ImportFallback < Operator; end
401
+ class Equivalent < Operator; end
332
402
 
333
403
  OPERATORS = [
334
404
  Or, And, Equal, NotEqual,
335
405
  Plus, Times,
336
406
  TextConcatenate, ListConcatenate,
337
407
  RecursiveRecordMerge, RightBiasedRecordMerge, RecursiveRecordTypeMerge,
338
- ImportFallback
408
+ ImportFallback,
409
+ Equivalent
339
410
  ].freeze
340
411
  end
341
412
 
@@ -344,9 +415,18 @@ module Dhall
344
415
 
345
416
  include(ValueSemantics.for_attributes do
346
417
  elements Util::ArrayOf.new(Expression, min: 1)
347
- element_type Either(nil, Expression), default: nil
418
+ type Either(nil, Expression), default: nil
348
419
  end)
349
420
 
421
+ def initialize(attrs)
422
+ if attrs.key?(:element_type)
423
+ et = attrs.delete(:element_type)
424
+ attrs[:type] = self.class.as_dhall.call(et) if et
425
+ end
426
+
427
+ super
428
+ end
429
+
350
430
  def self.of(*args, type: nil)
351
431
  if args.empty?
352
432
  EmptyList.new(element_type: type)
@@ -359,11 +439,13 @@ module Dhall
359
439
  Builtins[:List]
360
440
  end
361
441
 
362
- def type
363
- Dhall::Application.new(
364
- function: self.class.as_dhall,
365
- argument: element_type
366
- )
442
+ def element_type
443
+ if type.nil?
444
+ elsif type.is_a?(Application) && type.function == Builtins[:List]
445
+ type.argument
446
+ else
447
+ raise "Cannot get element_type of: #{type.inspect}"
448
+ end
367
449
  end
368
450
 
369
451
  def as_json
@@ -371,9 +453,10 @@ module Dhall
371
453
  end
372
454
 
373
455
  def map(type: nil, &block)
456
+ type = type.nil? ? nil : Builtins[:List].call(type.as_dhall)
374
457
  with(
375
- elements: elements.each_with_index.map(&block),
376
- element_type: type&.as_dhall
458
+ elements: elements.each_with_index.map(&block),
459
+ type: type
377
460
  )
378
461
  end
379
462
 
@@ -421,11 +504,22 @@ module Dhall
421
504
 
422
505
  class EmptyList < List
423
506
  include(ValueSemantics.for_attributes do
424
- element_type Either(nil, Expression)
507
+ type Either(nil, Expression)
425
508
  end)
426
509
 
510
+ def initialize(attrs)
511
+ if attrs.key?(:element_type)
512
+ et = attrs.delete(:element_type)
513
+ attrs[:type] = self.class.as_dhall.call(et) if et
514
+ end
515
+
516
+ super
517
+ end
518
+
427
519
  def as_json
428
520
  [4, element_type.as_json]
521
+ rescue
522
+ [28, type.as_json]
429
523
  end
430
524
 
431
525
  def map(type: nil)
@@ -460,6 +554,10 @@ module Dhall
460
554
  self
461
555
  end
462
556
 
557
+ def join(*)
558
+ ""
559
+ end
560
+
463
561
  def concat(other)
464
562
  other
465
563
  end
@@ -547,7 +645,7 @@ module Dhall
547
645
  include(ValueSemantics.for_attributes do
548
646
  record Expression
549
647
  input Expression
550
- type Either(Expression, nil)
648
+ type Either(Expression, nil), default: nil
551
649
  end)
552
650
 
553
651
  def as_json
@@ -556,6 +654,18 @@ module Dhall
556
654
  end
557
655
  end
558
656
 
657
+ class ToMap < Expression
658
+ include(ValueSemantics.for_attributes do
659
+ record Expression
660
+ type Either(Expression, nil), default: nil
661
+ end)
662
+
663
+ def as_json
664
+ [27, record.as_json] +
665
+ (type.nil? ? [] : [type.as_json])
666
+ end
667
+ end
668
+
559
669
  class RecordType < Expression
560
670
  include(ValueSemantics.for_attributes do
561
671
  record Util::HashOf.new(::String, Expression, min: 1)
@@ -793,11 +903,38 @@ module Dhall
793
903
  selectors Util::ArrayOf.new(::String, min: 1)
794
904
  end)
795
905
 
906
+ def self.for(record, selectors)
907
+ if selectors.empty?
908
+ EmptyRecordProjection.new(record: record)
909
+ else
910
+ new(record: record, selectors: selectors)
911
+ end
912
+ end
913
+
914
+ def fetch(selector)
915
+ record.fetch(selector)
916
+ end
917
+
796
918
  def as_json
797
919
  [10, record.as_json, *selectors]
798
920
  end
799
921
  end
800
922
 
923
+ class RecordProjectionByExpression < Expression
924
+ include(ValueSemantics.for_attributes do
925
+ record Expression
926
+ selector Expression
927
+ end)
928
+
929
+ def fetch(selector)
930
+ record.fetch(selector)
931
+ end
932
+
933
+ def as_json
934
+ [10, record.as_json, [selector.as_json]]
935
+ end
936
+ end
937
+
801
938
  class EmptyRecordProjection < Expression
802
939
  include(ValueSemantics.for_attributes do
803
940
  record Expression
@@ -968,8 +1105,8 @@ module Dhall
968
1105
  class If < Expression
969
1106
  include(ValueSemantics.for_attributes do
970
1107
  predicate Expression
971
- self.then Expression
972
- self.else Expression
1108
+ def_attr :then, Expression
1109
+ def_attr :else, Expression
973
1110
  end)
974
1111
 
975
1112
  def as_json
@@ -1189,91 +1326,92 @@ module Dhall
1189
1326
  class Import < Expression
1190
1327
  class IntegrityCheck
1191
1328
  include(ValueSemantics.for_attributes do
1192
- protocol Either("sha256", :nocheck)
1193
- data Either(::String, nil)
1329
+ code ::Integer
1330
+ digest ::String
1194
1331
  end)
1195
1332
 
1196
1333
  class FailureException < StandardError; end
1197
1334
 
1198
- def initialize(protocol=:nocheck, data=nil)
1199
- super(
1200
- protocol: protocol,
1201
- data: data
1202
- )
1335
+ def to_s
1336
+ "#{Multihashes::TABLE[code].sub(/\Asha2-/, "sha")}:#{hexdigest}"
1203
1337
  end
1204
1338
 
1205
- def to_s
1206
- "#{@protocol}:#{@data}"
1339
+ def hexdigest
1340
+ digest.unpack("H*").first.encode(Encoding::UTF_8)
1207
1341
  end
1208
1342
 
1209
- def check(expr)
1210
- return expr if @protocol == :nocheck
1343
+ def ipfs
1344
+ "/ipfs/b#{Base32.encode("\x01\x55" + as_json).downcase.sub(/=*$/, "")}"
1345
+ end
1211
1346
 
1347
+ def check(expr)
1212
1348
  expr = expr.normalize
1213
1349
  return expr if expr.cache_key == to_s
1214
1350
 
1215
- raise FailureException, "#{expr} does not match #{self}"
1351
+ raise FailureException, "#{expr} hash #{expr.cache_key}" \
1352
+ " does not match #{self}"
1216
1353
  end
1217
1354
 
1218
1355
  def as_json
1219
- @protocol == :nocheck ? nil : [@protocol, @data]
1356
+ Multihashes.encode(digest, Multihashes::TABLE[code])
1220
1357
  end
1221
1358
  end
1222
1359
 
1223
- class URI
1224
- include(ValueSemantics.for_attributes do
1225
- headers Either(nil, Expression)
1226
- authority ::String
1227
- path ArrayOf(::String)
1228
- query Either(nil, ::String)
1229
- end)
1360
+ class NoIntegrityCheck < IntegrityCheck
1361
+ def initialize; end
1230
1362
 
1231
- def initialize(headers, authority, *path, query)
1232
- super(
1233
- headers: headers,
1234
- authority: authority,
1235
- path: path,
1236
- query: query,
1237
- )
1363
+ def to_s
1364
+ ""
1238
1365
  end
1239
1366
 
1240
- def with(hash)
1241
- self.class.new(
1242
- hash.fetch(:headers, headers),
1243
- hash.fetch(:authority, authority),
1244
- *hash.fetch(:path, path),
1245
- hash.fetch(:query, query)
1246
- )
1367
+ def hexdigest; end
1368
+
1369
+ def check(expr)
1370
+ expr.normalize
1247
1371
  end
1248
1372
 
1249
- def self.from_uri(uri)
1250
- (uri.scheme == "https" ? Https : Http).new(
1251
- nil,
1252
- "#{uri.host}:#{uri.port}",
1253
- *uri.path.split(/\//)[1..-1],
1254
- uri.query,
1255
- nil
1256
- )
1373
+ def as_json
1374
+ nil
1375
+ end
1376
+ end
1377
+
1378
+ Location = LazyObject.new do
1379
+ UnionType.new(
1380
+ alternatives: {
1381
+ "Local" => Builtins[:Text],
1382
+ "Remote" => Builtins[:Text],
1383
+ "Environment" => Builtins[:Text],
1384
+ "Missing" => nil
1385
+ }
1386
+ )
1387
+ end
1388
+
1389
+ class URI
1390
+ include(ValueSemantics.for_attributes do
1391
+ uri ::URI
1392
+ headers Either(nil, Expression), default: nil
1393
+ end)
1394
+
1395
+ def with(attrs)
1396
+ if attrs.key?(:path)
1397
+ attrs[:uri] =
1398
+ uri + Util.path_components_to_uri(*attrs.delete(:path))
1399
+ end
1400
+
1401
+ super
1257
1402
  end
1258
1403
 
1259
1404
  def headers
1260
1405
  header_type = RecordType.new(
1261
1406
  record: {
1262
- "header" => Builtins[:Text],
1263
- "value" => Builtins[:Text]
1407
+ "mapKey" => Builtins[:Text],
1408
+ "mapValue" => Builtins[:Text]
1264
1409
  }
1265
1410
  )
1266
1411
 
1267
1412
  super || EmptyList.new(element_type: header_type)
1268
1413
  end
1269
1414
 
1270
- def uri
1271
- escaped_path = path.map do |c|
1272
- ::URI.encode_www_form_component(c).gsub("+", "%20")
1273
- end
1274
- URI("#{scheme}://#{authority}/#{escaped_path.join("/")}?#{query}")
1275
- end
1276
-
1277
1415
  def chain_onto(relative_to)
1278
1416
  if headers.is_a?(Import)
1279
1417
  with(headers: headers.with(path: headers.real_path(relative_to)))
@@ -1284,23 +1422,43 @@ module Dhall
1284
1422
 
1285
1423
  def canonical
1286
1424
  with(
1287
- path: (path[1..-1] + [""])
1288
- .reduce([[], path.first]) { |(pth, prev), c|
1425
+ path: (path[1..-1] + [""]).reduce([[], path.first]) { |(pth, prev), c|
1289
1426
  c == ".." ? [pth, prev] : [pth + [prev], c]
1290
1427
  }.first.reject { |c| c == "." }
1291
1428
  )
1292
1429
  end
1293
1430
 
1431
+ def port
1432
+ uri.port && uri.port != uri.default_port ? uri.port : nil
1433
+ end
1434
+
1435
+ def authority
1436
+ [
1437
+ uri.userinfo,
1438
+ [uri.host, port].compact.join(":")
1439
+ ].compact.join("@")
1440
+ end
1441
+
1294
1442
  def origin
1295
- "#{scheme}://#{authority}"
1443
+ "#{uri.scheme}://#{authority}"
1296
1444
  end
1297
1445
 
1298
1446
  def to_s
1299
1447
  uri.to_s
1300
1448
  end
1301
1449
 
1450
+ def location
1451
+ Union.from(Location, "Remote", to_s.as_dhall)
1452
+ end
1453
+
1454
+ def path
1455
+ path = uri.path.split(/\//, -1)
1456
+ path = path[1..-1] if path.length > 1 && path.first.empty?
1457
+ path
1458
+ end
1459
+
1302
1460
  def as_json
1303
- [@headers&.as_json, authority, *path, query]
1461
+ [@headers&.as_json, authority, *path, uri.query]
1304
1462
  end
1305
1463
  end
1306
1464
 
@@ -1308,20 +1466,12 @@ module Dhall
1308
1466
  def resolve(resolver)
1309
1467
  resolver.resolve_http(self)
1310
1468
  end
1311
-
1312
- def scheme
1313
- "http"
1314
- end
1315
1469
  end
1316
1470
 
1317
1471
  class Https < URI
1318
1472
  def resolve(resolver)
1319
1473
  resolver.resolve_https(self)
1320
1474
  end
1321
-
1322
- def scheme
1323
- "https"
1324
- end
1325
1475
  end
1326
1476
 
1327
1477
  class Path
@@ -1366,6 +1516,10 @@ module Dhall
1366
1516
  pathname.to_s
1367
1517
  end
1368
1518
 
1519
+ def location
1520
+ Union.from(Location, "Local", to_s.as_dhall)
1521
+ end
1522
+
1369
1523
  def as_json
1370
1524
  path
1371
1525
  end
@@ -1376,8 +1530,8 @@ module Dhall
1376
1530
  Pathname.new("/").join(*path)
1377
1531
  end
1378
1532
 
1379
- def to_uri(scheme, authority)
1380
- scheme.new(nil, authority, *path, nil)
1533
+ def to_uri(scheme, base_uri)
1534
+ scheme.new(uri: base_uri + Util.path_components_to_uri(*path))
1381
1535
  end
1382
1536
 
1383
1537
  def chain_onto(relative_to)
@@ -1394,6 +1548,10 @@ module Dhall
1394
1548
  Pathname.new(".").join(*path)
1395
1549
  end
1396
1550
 
1551
+ def to_s
1552
+ "./#{pathname}"
1553
+ end
1554
+
1397
1555
  def chain_onto(relative_to)
1398
1556
  relative_to.with(
1399
1557
  path: relative_to.path[0..-2] + path
@@ -1473,6 +1631,10 @@ module Dhall
1473
1631
  end}"
1474
1632
  end
1475
1633
 
1634
+ def location
1635
+ Union.from(Location, "Environment", to_s.as_dhall)
1636
+ end
1637
+
1476
1638
  def hash
1477
1639
  @var.hash
1478
1640
  end
@@ -1480,7 +1642,7 @@ module Dhall
1480
1642
  def eql?(other)
1481
1643
  other.is_a?(self.class) && other.var == var
1482
1644
  end
1483
- alias eql? ==
1645
+ alias == eql?
1484
1646
 
1485
1647
  def as_json
1486
1648
  @var
@@ -1506,6 +1668,15 @@ module Dhall
1506
1668
  "missing"
1507
1669
  end
1508
1670
 
1671
+ def location
1672
+ Union.from(Location, "Missing", nil)
1673
+ end
1674
+
1675
+ def eql?(other)
1676
+ other.class == self.class
1677
+ end
1678
+ alias == eql?
1679
+
1509
1680
  def as_json
1510
1681
  []
1511
1682
  end
@@ -1525,9 +1696,16 @@ module Dhall
1525
1696
  end
1526
1697
  end
1527
1698
 
1699
+ class AsLocation
1700
+ def self.call(*)
1701
+ raise "AsLocation is only a marker, you don't actually call it"
1702
+ end
1703
+ end
1704
+
1528
1705
  IMPORT_TYPES = [
1529
1706
  Expression,
1530
- Text
1707
+ Text,
1708
+ AsLocation
1531
1709
  ].freeze
1532
1710
 
1533
1711
  PATH_TYPES = [
@@ -1537,14 +1715,14 @@ module Dhall
1537
1715
  ].freeze
1538
1716
 
1539
1717
  include(ValueSemantics.for_attributes do
1540
- integrity_check IntegrityCheck, default: IntegrityCheck.new
1718
+ integrity_check IntegrityCheck, default: NoIntegrityCheck.new
1541
1719
  import_type Class
1542
1720
  path Either(*PATH_TYPES)
1543
1721
  end)
1544
1722
 
1545
1723
  def initialize(integrity_check, import_type, path)
1546
1724
  super(
1547
- integrity_check: integrity_check || IntegrityCheck.new,
1725
+ integrity_check: integrity_check || NoIntegrityCheck.new,
1548
1726
  import_type: import_type,
1549
1727
  path: path
1550
1728
  )
@@ -1562,15 +1740,18 @@ module Dhall
1562
1740
  path.chain_onto(relative_to).canonical
1563
1741
  end
1564
1742
 
1565
- def parse_and_check(raw, deadline: Util::NoDeadline.new)
1566
- integrity_check.check(import_type.call(raw, deadline: deadline))
1743
+ def parse_resolve_check(raw, deadline: Util::NoDeadline.new, **kwargs)
1744
+ import_type.call(raw, deadline: deadline).resolve(**kwargs).then do |e|
1745
+ integrity_check.check(TypeChecker.annotate(e))
1746
+ end
1567
1747
  end
1568
1748
 
1569
1749
  def cache_key(relative_to)
1570
- if integrity_check.protocol == :nocheck
1750
+ key = integrity_check.to_s
1751
+ if key.empty?
1571
1752
  real_path(relative_to)
1572
1753
  else
1573
- integrity_check.to_s
1754
+ key
1574
1755
  end
1575
1756
  end
1576
1757
 
@@ -1609,10 +1790,10 @@ module Dhall
1609
1790
 
1610
1791
  def flatten
1611
1792
  flattened = body.is_a?(LetIn) ? body.flatten : body
1612
- if flattened.is_a?(LetIn) || flattened.is_a?(LetBlock)
1613
- LetBlock.for(lets: [let] + flattened.lets, body: flattened.body)
1793
+ if flattened.is_a?(LetBlock)
1794
+ LetBlock.new(lets: lets + flattened.lets, body: flattened.body)
1614
1795
  else
1615
- self
1796
+ LetBlock.new(lets: lets, body: body)
1616
1797
  end
1617
1798
  end
1618
1799
 
@@ -1635,28 +1816,16 @@ module Dhall
1635
1816
  end
1636
1817
 
1637
1818
  def as_json
1638
- [25, *let.as_json, body.as_json]
1819
+ flatten.as_json
1639
1820
  end
1640
1821
  end
1641
1822
 
1642
- class LetBlock < Expression
1823
+ class LetBlock
1643
1824
  include(ValueSemantics.for_attributes do
1644
- lets Util::ArrayOf.new(Let, min: 2)
1825
+ lets Util::ArrayOf.new(Let)
1645
1826
  body Expression
1646
1827
  end)
1647
1828
 
1648
- def self.for(lets:, body:)
1649
- if lets.length == 1
1650
- LetIn.new(let: lets.first, body: body)
1651
- else
1652
- new(lets: lets, body: body)
1653
- end
1654
- end
1655
-
1656
- def flatten
1657
- unflatten.flatten
1658
- end
1659
-
1660
1829
  def unflatten
1661
1830
  lets.reverse.reduce(body) do |inside, let|
1662
1831
  letin = LetIn.new(let: let, body: inside)
@@ -1664,10 +1833,6 @@ module Dhall
1664
1833
  end
1665
1834
  end
1666
1835
 
1667
- def desugar
1668
- unflatten(&:desugar)
1669
- end
1670
-
1671
1836
  def as_json
1672
1837
  [25, *lets.flat_map(&:as_json), body.as_json]
1673
1838
  end
@@ -1683,4 +1848,14 @@ module Dhall
1683
1848
  [26, value.as_json, type.as_json]
1684
1849
  end
1685
1850
  end
1851
+
1852
+ class Assertion < Expression
1853
+ include(ValueSemantics.for_attributes do
1854
+ type Expression
1855
+ end)
1856
+
1857
+ def as_json
1858
+ [19, type.as_json]
1859
+ end
1860
+ end
1686
1861
  end