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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30ff6e0ad066b23996b9a31b21e7f1a30b86b265
4
- data.tar.gz: 88efb36ee05894a74df3b691d67774b8e0eea185
3
+ metadata.gz: 55053ce451e1b675998712636c725380329d1fe6
4
+ data.tar.gz: d98038e234871e81f8c0ce3f6d2a8f7c941b8278
5
5
  SHA512:
6
- metadata.gz: ff197049f1d4ceb3e1742a4e3b44491192170c4bb1e32b7aef6bbaeb643f16b828ffdee1d78eaa628a9f0dd9d5dedd0f4c796556b2e72b92ed0705a0e8306430
7
- data.tar.gz: e92aad6b3921f4bd25ebdf8f20204b95ceec8814250ed90b5424b70a75991ca68de8bd60b0c2cf982541c560f9e1ba135f87f0b05f685d767588150b051c465f
6
+ metadata.gz: 4735802d9beb7c796d06ba6c887f5776ac24f12342ad754d911cc36593fb730f0c4d861b653b3667ad1590835014ffcf865e1aa4bd5a56f3c4d9b4e49274d808
7
+ data.tar.gz: 386cda30b6cd93ea7b6236bab460681554240355e25609c4791cb7d85cf6ff07f3b6a3d6b2a3727c2d6d9d8c2123105b4bcf1a03f1cb0272baa2651b4c0c7159
@@ -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
 
@@ -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)
@@ -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)
@@ -25,8 +25,11 @@ 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.1.3"
30
33
  spec.add_dependency "promise.rb", "~> 0.7.4"
31
34
  spec.add_dependency "value_semantics", "~> 3.0"
32
35
 
@@ -9,6 +9,7 @@ require "dhall/normalize"
9
9
  require "dhall/parser"
10
10
  require "dhall/resolve"
11
11
  require "dhall/typecheck"
12
+ require "dhall/types"
12
13
 
13
14
  module Dhall
14
15
  using Dhall::AsDhall
@@ -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
@@ -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)
@@ -128,7 +130,7 @@ module Dhall
128
130
  def flatten
129
131
  f, args = if function.is_a?(Application)
130
132
  function.flatten
131
- elsif function.is_a?(Builtin) &&
133
+ elsif function.is_a?(BuiltinFunction) &&
132
134
  (unfilled = function.unfill).is_a?(Application)
133
135
  unfilled.flatten
134
136
  else
@@ -216,7 +218,29 @@ module Dhall
216
218
  end
217
219
  end
218
220
 
219
- class FunctionProxy < Function
221
+ class RubyObjectRaw < Expression
222
+ def initialize(object)
223
+ @object = object
224
+ end
225
+
226
+ def unwrap
227
+ @object
228
+ end
229
+
230
+ def respond_to_missing?(m)
231
+ super || @object.respond_to?(m)
232
+ end
233
+
234
+ def method_missing(m, *args, &block)
235
+ if @object.respond_to?(m)
236
+ @object.public_send(m, *args, &block)
237
+ else
238
+ super
239
+ end
240
+ end
241
+ end
242
+
243
+ class FunctionProxyRaw < Function
220
244
  def initialize(callable, curry: true)
221
245
  @callable = if !curry
222
246
  callable
@@ -230,7 +254,7 @@ module Dhall
230
254
  end
231
255
 
232
256
  def call(*args, &block)
233
- @callable.call(*args.map { |arg| arg&.as_dhall }, &block).as_dhall
257
+ RubyObjectRaw.new(@callable.call(*args.map { |arg| arg&.as_dhall }, &block))
234
258
  end
235
259
 
236
260
  def as_json
@@ -238,6 +262,12 @@ module Dhall
238
262
  end
239
263
  end
240
264
 
265
+ class FunctionProxy < FunctionProxyRaw
266
+ def call(*args, &block)
267
+ super.unwrap.as_dhall
268
+ end
269
+ end
270
+
241
271
  class Bool < Expression
242
272
  include(ValueSemantics.for_attributes do
243
273
  value Bool()
@@ -344,9 +374,18 @@ module Dhall
344
374
 
345
375
  include(ValueSemantics.for_attributes do
346
376
  elements Util::ArrayOf.new(Expression, min: 1)
347
- element_type Either(nil, Expression), default: nil
377
+ type Either(nil, Expression), default: nil
348
378
  end)
349
379
 
380
+ def initialize(attrs)
381
+ if attrs.key?(:element_type)
382
+ et = attrs.delete(:element_type)
383
+ attrs[:type] = self.class.as_dhall.call(et) if et
384
+ end
385
+
386
+ super
387
+ end
388
+
350
389
  def self.of(*args, type: nil)
351
390
  if args.empty?
352
391
  EmptyList.new(element_type: type)
@@ -359,11 +398,13 @@ module Dhall
359
398
  Builtins[:List]
360
399
  end
361
400
 
362
- def type
363
- Dhall::Application.new(
364
- function: self.class.as_dhall,
365
- argument: element_type
366
- )
401
+ def element_type
402
+ if type.nil?
403
+ elsif type.is_a?(Application) && type.function == Builtins[:List]
404
+ type.argument
405
+ else
406
+ raise "Cannot get element_type of: #{type.inspect}"
407
+ end
367
408
  end
368
409
 
369
410
  def as_json
@@ -371,9 +412,10 @@ module Dhall
371
412
  end
372
413
 
373
414
  def map(type: nil, &block)
415
+ type = type.nil? ? nil : Builtins[:List].call(type.as_dhall)
374
416
  with(
375
- elements: elements.each_with_index.map(&block),
376
- element_type: type&.as_dhall
417
+ elements: elements.each_with_index.map(&block),
418
+ type: type
377
419
  )
378
420
  end
379
421
 
@@ -421,11 +463,22 @@ module Dhall
421
463
 
422
464
  class EmptyList < List
423
465
  include(ValueSemantics.for_attributes do
424
- element_type Either(nil, Expression)
466
+ type Either(nil, Expression)
425
467
  end)
426
468
 
469
+ def initialize(attrs)
470
+ if attrs.key?(:element_type)
471
+ et = attrs.delete(:element_type)
472
+ attrs[:type] = self.class.as_dhall.call(et) if et
473
+ end
474
+
475
+ super
476
+ end
477
+
427
478
  def as_json
428
479
  [4, element_type.as_json]
480
+ rescue
481
+ [28, type.as_json]
429
482
  end
430
483
 
431
484
  def map(type: nil)
@@ -460,6 +513,10 @@ module Dhall
460
513
  self
461
514
  end
462
515
 
516
+ def join(*)
517
+ ""
518
+ end
519
+
463
520
  def concat(other)
464
521
  other
465
522
  end
@@ -547,7 +604,7 @@ module Dhall
547
604
  include(ValueSemantics.for_attributes do
548
605
  record Expression
549
606
  input Expression
550
- type Either(Expression, nil)
607
+ type Either(Expression, nil), default: nil
551
608
  end)
552
609
 
553
610
  def as_json
@@ -556,6 +613,18 @@ module Dhall
556
613
  end
557
614
  end
558
615
 
616
+ class ToMap < Expression
617
+ include(ValueSemantics.for_attributes do
618
+ record Expression
619
+ type Either(Expression, nil), default: nil
620
+ end)
621
+
622
+ def as_json
623
+ [27, record.as_json] +
624
+ (type.nil? ? [] : [type.as_json])
625
+ end
626
+ end
627
+
559
628
  class RecordType < Expression
560
629
  include(ValueSemantics.for_attributes do
561
630
  record Util::HashOf.new(::String, Expression, min: 1)
@@ -793,11 +862,30 @@ module Dhall
793
862
  selectors Util::ArrayOf.new(::String, min: 1)
794
863
  end)
795
864
 
865
+ def self.for(record, selectors)
866
+ if selectors.empty?
867
+ EmptyRecordProjection.new(record: record)
868
+ else
869
+ new(record: record, selectors: selectors)
870
+ end
871
+ end
872
+
796
873
  def as_json
797
874
  [10, record.as_json, *selectors]
798
875
  end
799
876
  end
800
877
 
878
+ class RecordProjectionByExpression < Expression
879
+ include(ValueSemantics.for_attributes do
880
+ record Expression
881
+ selector Expression
882
+ end)
883
+
884
+ def as_json
885
+ [10, record.as_json, [selector.as_json]]
886
+ end
887
+ end
888
+
801
889
  class EmptyRecordProjection < Expression
802
890
  include(ValueSemantics.for_attributes do
803
891
  record Expression
@@ -1189,26 +1277,25 @@ module Dhall
1189
1277
  class Import < Expression
1190
1278
  class IntegrityCheck
1191
1279
  include(ValueSemantics.for_attributes do
1192
- protocol Either("sha256", :nocheck)
1193
- data Either(::String, nil)
1280
+ code ::Integer
1281
+ digest ::String
1194
1282
  end)
1195
1283
 
1196
1284
  class FailureException < StandardError; end
1197
1285
 
1198
- def initialize(protocol=:nocheck, data=nil)
1199
- super(
1200
- protocol: protocol,
1201
- data: data
1202
- )
1286
+ def to_s
1287
+ "#{Multihashes::TABLE[code].sub(/\Asha2-/, "sha")}:#{hexdigest}"
1203
1288
  end
1204
1289
 
1205
- def to_s
1206
- "#{@protocol}:#{@data}"
1290
+ def hexdigest
1291
+ digest.unpack("H*").first.encode(Encoding::UTF_8)
1207
1292
  end
1208
1293
 
1209
- def check(expr)
1210
- return expr if @protocol == :nocheck
1294
+ def ipfs
1295
+ "/ipfs/b#{Base32.encode("\x01\x55" + as_json).downcase.sub(/=*$/, "")}"
1296
+ end
1211
1297
 
1298
+ def check(expr)
1212
1299
  expr = expr.normalize
1213
1300
  return expr if expr.cache_key == to_s
1214
1301
 
@@ -1216,64 +1303,65 @@ module Dhall
1216
1303
  end
1217
1304
 
1218
1305
  def as_json
1219
- @protocol == :nocheck ? nil : [@protocol, @data]
1306
+ Multihashes.encode(digest, Multihashes::TABLE[code])
1220
1307
  end
1221
1308
  end
1222
1309
 
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)
1310
+ class NoIntegrityCheck < IntegrityCheck
1311
+ def initialize; end
1230
1312
 
1231
- def initialize(headers, authority, *path, query)
1232
- super(
1233
- headers: headers,
1234
- authority: authority,
1235
- path: path,
1236
- query: query,
1237
- )
1313
+ def to_s
1314
+ ""
1238
1315
  end
1239
1316
 
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
- )
1317
+ def hexdigest; end
1318
+
1319
+ def check(expr)
1320
+ expr
1247
1321
  end
1248
1322
 
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
- )
1323
+ def as_json
1324
+ nil
1325
+ end
1326
+ end
1327
+
1328
+ Location = LazyObject.new do
1329
+ UnionType.new(
1330
+ alternatives: {
1331
+ "Local" => Builtins[:Text],
1332
+ "Remote" => Builtins[:Text],
1333
+ "Environment" => Builtins[:Text],
1334
+ "Missing" => nil
1335
+ }
1336
+ )
1337
+ end
1338
+
1339
+ class URI
1340
+ include(ValueSemantics.for_attributes do
1341
+ uri ::URI
1342
+ headers Either(nil, Expression), default: nil
1343
+ end)
1344
+
1345
+ def with(attrs)
1346
+ if attrs.key?(:path)
1347
+ attrs[:uri] =
1348
+ uri + Util.path_components_to_uri(*attrs.delete(:path))
1349
+ end
1350
+
1351
+ super
1257
1352
  end
1258
1353
 
1259
1354
  def headers
1260
1355
  header_type = RecordType.new(
1261
1356
  record: {
1262
- "header" => Builtins[:Text],
1263
- "value" => Builtins[:Text]
1357
+ "mapKey" => Builtins[:Text],
1358
+ "mapValue" => Builtins[:Text]
1264
1359
  }
1265
1360
  )
1266
1361
 
1267
1362
  super || EmptyList.new(element_type: header_type)
1268
1363
  end
1269
1364
 
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
1365
  def chain_onto(relative_to)
1278
1366
  if headers.is_a?(Import)
1279
1367
  with(headers: headers.with(path: headers.real_path(relative_to)))
@@ -1284,23 +1372,43 @@ module Dhall
1284
1372
 
1285
1373
  def canonical
1286
1374
  with(
1287
- path: (path[1..-1] + [""])
1288
- .reduce([[], path.first]) { |(pth, prev), c|
1375
+ path: (path[1..-1] + [""]).reduce([[], path.first]) { |(pth, prev), c|
1289
1376
  c == ".." ? [pth, prev] : [pth + [prev], c]
1290
1377
  }.first.reject { |c| c == "." }
1291
1378
  )
1292
1379
  end
1293
1380
 
1381
+ def port
1382
+ uri.port && uri.port != uri.default_port ? uri.port : nil
1383
+ end
1384
+
1385
+ def authority
1386
+ [
1387
+ uri.userinfo,
1388
+ [uri.host, port].compact.join(":")
1389
+ ].compact.join("@")
1390
+ end
1391
+
1294
1392
  def origin
1295
- "#{scheme}://#{authority}"
1393
+ "#{uri.scheme}://#{authority}"
1296
1394
  end
1297
1395
 
1298
1396
  def to_s
1299
1397
  uri.to_s
1300
1398
  end
1301
1399
 
1400
+ def location
1401
+ Union.from(Location, "Remote", to_s.as_dhall)
1402
+ end
1403
+
1404
+ def path
1405
+ path = uri.path.split(/\//, -1).map(&::URI.method(:unescape))
1406
+ path = path[1..-1] if path.length > 1 && path.first.empty?
1407
+ path
1408
+ end
1409
+
1302
1410
  def as_json
1303
- [@headers&.as_json, authority, *path, query]
1411
+ [@headers&.as_json, authority, *path, uri.query]
1304
1412
  end
1305
1413
  end
1306
1414
 
@@ -1308,20 +1416,12 @@ module Dhall
1308
1416
  def resolve(resolver)
1309
1417
  resolver.resolve_http(self)
1310
1418
  end
1311
-
1312
- def scheme
1313
- "http"
1314
- end
1315
1419
  end
1316
1420
 
1317
1421
  class Https < URI
1318
1422
  def resolve(resolver)
1319
1423
  resolver.resolve_https(self)
1320
1424
  end
1321
-
1322
- def scheme
1323
- "https"
1324
- end
1325
1425
  end
1326
1426
 
1327
1427
  class Path
@@ -1366,6 +1466,10 @@ module Dhall
1366
1466
  pathname.to_s
1367
1467
  end
1368
1468
 
1469
+ def location
1470
+ Union.from(Location, "Local", to_s.as_dhall)
1471
+ end
1472
+
1369
1473
  def as_json
1370
1474
  path
1371
1475
  end
@@ -1376,8 +1480,8 @@ module Dhall
1376
1480
  Pathname.new("/").join(*path)
1377
1481
  end
1378
1482
 
1379
- def to_uri(scheme, authority)
1380
- scheme.new(nil, authority, *path, nil)
1483
+ def to_uri(scheme, base_uri)
1484
+ scheme.new(uri: base_uri + Util.path_components_to_uri(*path))
1381
1485
  end
1382
1486
 
1383
1487
  def chain_onto(relative_to)
@@ -1394,6 +1498,10 @@ module Dhall
1394
1498
  Pathname.new(".").join(*path)
1395
1499
  end
1396
1500
 
1501
+ def to_s
1502
+ "./#{pathname}"
1503
+ end
1504
+
1397
1505
  def chain_onto(relative_to)
1398
1506
  relative_to.with(
1399
1507
  path: relative_to.path[0..-2] + path
@@ -1473,6 +1581,10 @@ module Dhall
1473
1581
  end}"
1474
1582
  end
1475
1583
 
1584
+ def location
1585
+ Union.from(Location, "Environment", to_s.as_dhall)
1586
+ end
1587
+
1476
1588
  def hash
1477
1589
  @var.hash
1478
1590
  end
@@ -1480,7 +1592,7 @@ module Dhall
1480
1592
  def eql?(other)
1481
1593
  other.is_a?(self.class) && other.var == var
1482
1594
  end
1483
- alias eql? ==
1595
+ alias == eql?
1484
1596
 
1485
1597
  def as_json
1486
1598
  @var
@@ -1506,6 +1618,15 @@ module Dhall
1506
1618
  "missing"
1507
1619
  end
1508
1620
 
1621
+ def location
1622
+ Union.from(Location, "Missing", nil)
1623
+ end
1624
+
1625
+ def eql?(other)
1626
+ other.class == self.class
1627
+ end
1628
+ alias == eql?
1629
+
1509
1630
  def as_json
1510
1631
  []
1511
1632
  end
@@ -1525,9 +1646,16 @@ module Dhall
1525
1646
  end
1526
1647
  end
1527
1648
 
1649
+ class AsLocation
1650
+ def self.call(*)
1651
+ raise "AsLocation is only a marker, you don't actually call it"
1652
+ end
1653
+ end
1654
+
1528
1655
  IMPORT_TYPES = [
1529
1656
  Expression,
1530
- Text
1657
+ Text,
1658
+ AsLocation
1531
1659
  ].freeze
1532
1660
 
1533
1661
  PATH_TYPES = [
@@ -1537,14 +1665,14 @@ module Dhall
1537
1665
  ].freeze
1538
1666
 
1539
1667
  include(ValueSemantics.for_attributes do
1540
- integrity_check IntegrityCheck, default: IntegrityCheck.new
1668
+ integrity_check IntegrityCheck, default: NoIntegrityCheck.new
1541
1669
  import_type Class
1542
1670
  path Either(*PATH_TYPES)
1543
1671
  end)
1544
1672
 
1545
1673
  def initialize(integrity_check, import_type, path)
1546
1674
  super(
1547
- integrity_check: integrity_check || IntegrityCheck.new,
1675
+ integrity_check: integrity_check || NoIntegrityCheck.new,
1548
1676
  import_type: import_type,
1549
1677
  path: path
1550
1678
  )
@@ -1567,10 +1695,11 @@ module Dhall
1567
1695
  end
1568
1696
 
1569
1697
  def cache_key(relative_to)
1570
- if integrity_check.protocol == :nocheck
1698
+ key = integrity_check.to_s
1699
+ if key.empty?
1571
1700
  real_path(relative_to)
1572
1701
  else
1573
- integrity_check.to_s
1702
+ key
1574
1703
  end
1575
1704
  end
1576
1705