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/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,18 +36,13 @@ module Dhall
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def *(other)
|
36
|
-
|
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)
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
def <<(other)
|
45
|
-
Operator::TextConcatenate.new(lhs: self, rhs: other)
|
46
|
-
end
|
47
|
-
|
48
46
|
def concat(other)
|
49
47
|
Operator::ListConcatenate.new(lhs: self, rhs: other)
|
50
48
|
end
|
@@ -72,7 +70,7 @@ module Dhall
|
|
72
70
|
def dhall_eq(other)
|
73
71
|
if self == other
|
74
72
|
Bool.new(value: true)
|
75
|
-
elsif other.
|
73
|
+
elsif other == Bool.new(value: true)
|
76
74
|
other.dhall_eq(self)
|
77
75
|
else
|
78
76
|
Operator::Equal.new(lhs: self, rhs: other)
|
@@ -106,6 +104,14 @@ module Dhall
|
|
106
104
|
end
|
107
105
|
end
|
108
106
|
|
107
|
+
def annotate(type)
|
108
|
+
TypeAnnotation.new(value: self, type: type)
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_s
|
112
|
+
inspect
|
113
|
+
end
|
114
|
+
|
109
115
|
def as_dhall
|
110
116
|
self
|
111
117
|
end
|
@@ -118,9 +124,7 @@ module Dhall
|
|
118
124
|
end)
|
119
125
|
|
120
126
|
def self.for(function:, argument:)
|
121
|
-
if function ==
|
122
|
-
Optional.new(value: argument)
|
123
|
-
elsif function == Variable["None"]
|
127
|
+
if function == Builtins[:None]
|
124
128
|
OptionalNone.new(value_type: argument)
|
125
129
|
else
|
126
130
|
new(function: function, argument: argument)
|
@@ -130,7 +134,7 @@ module Dhall
|
|
130
134
|
def flatten
|
131
135
|
f, args = if function.is_a?(Application)
|
132
136
|
function.flatten
|
133
|
-
elsif function.is_a?(
|
137
|
+
elsif function.is_a?(BuiltinFunction) &&
|
134
138
|
(unfilled = function.unfill).is_a?(Application)
|
135
139
|
unfilled.flatten
|
136
140
|
else
|
@@ -148,7 +152,7 @@ module Dhall
|
|
148
152
|
|
149
153
|
class Function < Expression
|
150
154
|
include(ValueSemantics.for_attributes do
|
151
|
-
var
|
155
|
+
var ::String
|
152
156
|
type Either(nil, Expression) # nil is not allowed in proper Dhall
|
153
157
|
body Expression
|
154
158
|
end)
|
@@ -163,7 +167,8 @@ module Dhall
|
|
163
167
|
end
|
164
168
|
end
|
165
169
|
|
166
|
-
def call(*args)
|
170
|
+
def call(*args, &block)
|
171
|
+
args += [block] if block
|
167
172
|
args.map! { |arg| arg&.as_dhall }
|
168
173
|
return super if args.length > 1
|
169
174
|
|
@@ -174,6 +179,29 @@ module Dhall
|
|
174
179
|
end
|
175
180
|
|
176
181
|
alias [] call
|
182
|
+
alias === call
|
183
|
+
|
184
|
+
def <<(other)
|
185
|
+
FunctionProxy.new(
|
186
|
+
->(*args, &block) { call(other.call(*args, &block)) },
|
187
|
+
curry: false
|
188
|
+
)
|
189
|
+
end
|
190
|
+
|
191
|
+
def >>(other)
|
192
|
+
FunctionProxy.new(
|
193
|
+
->(*args, &block) { other.call(call(*args, &block)) },
|
194
|
+
curry: false
|
195
|
+
)
|
196
|
+
end
|
197
|
+
|
198
|
+
def binding
|
199
|
+
to_proc.binding
|
200
|
+
end
|
201
|
+
|
202
|
+
def curry
|
203
|
+
self
|
204
|
+
end
|
177
205
|
|
178
206
|
def as_json
|
179
207
|
if var == "_"
|
@@ -194,6 +222,56 @@ module Dhall
|
|
194
222
|
end
|
195
223
|
end
|
196
224
|
|
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
|
248
|
+
def initialize(callable, curry: true)
|
249
|
+
@callable = if !curry
|
250
|
+
callable
|
251
|
+
elsif callable.respond_to?(:curry)
|
252
|
+
callable.curry
|
253
|
+
elsif callable.respond_to?(:to_proc)
|
254
|
+
callable.to_proc.curry
|
255
|
+
else
|
256
|
+
callable.method(:call).to_proc.curry
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def call(*args, &block)
|
261
|
+
RubyObjectRaw.new(@callable.call(*args.map { |arg| arg&.as_dhall }, &block))
|
262
|
+
end
|
263
|
+
|
264
|
+
def as_json
|
265
|
+
raise "Cannot serialize #{self}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
class FunctionProxy < FunctionProxyRaw
|
270
|
+
def call(*args, &block)
|
271
|
+
super.unwrap.as_dhall
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
197
275
|
class Bool < Expression
|
198
276
|
include(ValueSemantics.for_attributes do
|
199
277
|
value Bool()
|
@@ -234,6 +312,10 @@ module Dhall
|
|
234
312
|
def as_json
|
235
313
|
value
|
236
314
|
end
|
315
|
+
|
316
|
+
def self.as_dhall
|
317
|
+
Builtins[:Bool]
|
318
|
+
end
|
237
319
|
end
|
238
320
|
|
239
321
|
class Variable < Expression
|
@@ -253,8 +335,6 @@ module Dhall
|
|
253
335
|
def as_json
|
254
336
|
if name == "_"
|
255
337
|
index
|
256
|
-
elsif index.zero?
|
257
|
-
name
|
258
338
|
else
|
259
339
|
[name, index]
|
260
340
|
end
|
@@ -271,6 +351,33 @@ module Dhall
|
|
271
351
|
[3, OPERATORS.index(self.class), lhs.as_json, rhs.as_json]
|
272
352
|
end
|
273
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
|
+
|
274
381
|
class Or < Operator; end
|
275
382
|
class And < Operator; end
|
276
383
|
class Equal < Operator; end
|
@@ -279,17 +386,27 @@ module Dhall
|
|
279
386
|
class Times < Operator; end
|
280
387
|
class TextConcatenate < Operator; end
|
281
388
|
class ListConcatenate < Operator; end
|
282
|
-
class RecursiveRecordMerge < Operator
|
283
|
-
|
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
|
284
399
|
class RecursiveRecordTypeMerge < Operator; end
|
285
400
|
class ImportFallback < Operator; end
|
401
|
+
class Equivalent < Operator; end
|
286
402
|
|
287
403
|
OPERATORS = [
|
288
404
|
Or, And, Equal, NotEqual,
|
289
405
|
Plus, Times,
|
290
406
|
TextConcatenate, ListConcatenate,
|
291
407
|
RecursiveRecordMerge, RightBiasedRecordMerge, RecursiveRecordTypeMerge,
|
292
|
-
ImportFallback
|
408
|
+
ImportFallback,
|
409
|
+
Equivalent
|
293
410
|
].freeze
|
294
411
|
end
|
295
412
|
|
@@ -298,9 +415,18 @@ module Dhall
|
|
298
415
|
|
299
416
|
include(ValueSemantics.for_attributes do
|
300
417
|
elements Util::ArrayOf.new(Expression, min: 1)
|
301
|
-
|
418
|
+
type Either(nil, Expression), default: nil
|
302
419
|
end)
|
303
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
|
+
|
304
430
|
def self.of(*args, type: nil)
|
305
431
|
if args.empty?
|
306
432
|
EmptyList.new(element_type: type)
|
@@ -309,11 +435,17 @@ module Dhall
|
|
309
435
|
end
|
310
436
|
end
|
311
437
|
|
312
|
-
def
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
438
|
+
def self.as_dhall
|
439
|
+
Builtins[:List]
|
440
|
+
end
|
441
|
+
|
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
|
317
449
|
end
|
318
450
|
|
319
451
|
def as_json
|
@@ -321,7 +453,11 @@ module Dhall
|
|
321
453
|
end
|
322
454
|
|
323
455
|
def map(type: nil, &block)
|
324
|
-
|
456
|
+
type = type.nil? ? nil : Builtins[:List].call(type.as_dhall)
|
457
|
+
with(
|
458
|
+
elements: elements.each_with_index.map(&block),
|
459
|
+
type: type
|
460
|
+
)
|
325
461
|
end
|
326
462
|
|
327
463
|
def each(&block)
|
@@ -368,11 +504,22 @@ module Dhall
|
|
368
504
|
|
369
505
|
class EmptyList < List
|
370
506
|
include(ValueSemantics.for_attributes do
|
371
|
-
|
507
|
+
type Either(nil, Expression)
|
372
508
|
end)
|
373
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
|
+
|
374
519
|
def as_json
|
375
520
|
[4, element_type.as_json]
|
521
|
+
rescue
|
522
|
+
[28, type.as_json]
|
376
523
|
end
|
377
524
|
|
378
525
|
def map(type: nil)
|
@@ -407,6 +554,10 @@ module Dhall
|
|
407
554
|
self
|
408
555
|
end
|
409
556
|
|
557
|
+
def join(*)
|
558
|
+
""
|
559
|
+
end
|
560
|
+
|
410
561
|
def concat(other)
|
411
562
|
other
|
412
563
|
end
|
@@ -426,6 +577,10 @@ module Dhall
|
|
426
577
|
end
|
427
578
|
end
|
428
579
|
|
580
|
+
def self.as_dhall
|
581
|
+
Builtins[:Natural]
|
582
|
+
end
|
583
|
+
|
429
584
|
def initialize(normalized: false, **attrs)
|
430
585
|
@normalized = normalized
|
431
586
|
super(**attrs)
|
@@ -435,7 +590,7 @@ module Dhall
|
|
435
590
|
return unless value_type
|
436
591
|
|
437
592
|
Dhall::Application.new(
|
438
|
-
function:
|
593
|
+
function: Builtins[:Optional],
|
439
594
|
argument: value_type
|
440
595
|
)
|
441
596
|
end
|
@@ -462,6 +617,10 @@ module Dhall
|
|
462
617
|
value_type Expression
|
463
618
|
end)
|
464
619
|
|
620
|
+
def self.as_dhall
|
621
|
+
Builtins[:None]
|
622
|
+
end
|
623
|
+
|
465
624
|
def map(type: nil)
|
466
625
|
type.nil? ? self : with(value_type: type)
|
467
626
|
end
|
@@ -475,7 +634,10 @@ module Dhall
|
|
475
634
|
end
|
476
635
|
|
477
636
|
def as_json
|
478
|
-
|
637
|
+
Application.new(
|
638
|
+
function: self.class.as_dhall,
|
639
|
+
argument: value_type
|
640
|
+
).as_json
|
479
641
|
end
|
480
642
|
end
|
481
643
|
|
@@ -483,7 +645,7 @@ module Dhall
|
|
483
645
|
include(ValueSemantics.for_attributes do
|
484
646
|
record Expression
|
485
647
|
input Expression
|
486
|
-
type Either(Expression, nil)
|
648
|
+
type Either(Expression, nil), default: nil
|
487
649
|
end)
|
488
650
|
|
489
651
|
def as_json
|
@@ -492,6 +654,18 @@ module Dhall
|
|
492
654
|
end
|
493
655
|
end
|
494
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
|
+
|
495
669
|
class RecordType < Expression
|
496
670
|
include(ValueSemantics.for_attributes do
|
497
671
|
record Util::HashOf.new(::String, Expression, min: 1)
|
@@ -729,11 +903,38 @@ module Dhall
|
|
729
903
|
selectors Util::ArrayOf.new(::String, min: 1)
|
730
904
|
end)
|
731
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
|
+
|
732
918
|
def as_json
|
733
919
|
[10, record.as_json, *selectors]
|
734
920
|
end
|
735
921
|
end
|
736
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
|
+
|
737
938
|
class EmptyRecordProjection < Expression
|
738
939
|
include(ValueSemantics.for_attributes do
|
739
940
|
record Expression
|
@@ -750,9 +951,22 @@ module Dhall
|
|
750
951
|
|
751
952
|
class UnionType < Expression
|
752
953
|
include(ValueSemantics.for_attributes do
|
753
|
-
alternatives Util::HashOf.new(::String, Either(Expression, nil))
|
954
|
+
alternatives Util::HashOf.new(::String, Either(Expression, nil)), default: {}
|
754
955
|
end)
|
755
956
|
|
957
|
+
def empty?
|
958
|
+
alternatives.empty?
|
959
|
+
end
|
960
|
+
|
961
|
+
def [](k)
|
962
|
+
alternatives.fetch(k)
|
963
|
+
end
|
964
|
+
|
965
|
+
def without(*keys)
|
966
|
+
keys.map!(&:to_s)
|
967
|
+
with(alternatives: alternatives.reject { |k, _| keys.include?(k) })
|
968
|
+
end
|
969
|
+
|
756
970
|
def record
|
757
971
|
alternatives
|
758
972
|
end
|
@@ -765,8 +979,8 @@ module Dhall
|
|
765
979
|
self == other
|
766
980
|
end
|
767
981
|
|
768
|
-
def merge(other)
|
769
|
-
with(alternatives: alternatives.merge(other.alternatives))
|
982
|
+
def merge(other, &block)
|
983
|
+
with(alternatives: alternatives.merge(other.alternatives, &block))
|
770
984
|
end
|
771
985
|
|
772
986
|
def fetch(k, default=nil)
|
@@ -780,10 +994,9 @@ module Dhall
|
|
780
994
|
end
|
781
995
|
|
782
996
|
def get_constructor(selector)
|
783
|
-
var = Util::BuiltinName === selector ? "_" : selector
|
784
997
|
type = alternatives.fetch(selector)
|
785
|
-
body = Union.from(self, selector, Variable[
|
786
|
-
Function.new(var:
|
998
|
+
body = Union.from(self, selector, Variable[selector])
|
999
|
+
Function.new(var: selector, type: type, body: body)
|
787
1000
|
end
|
788
1001
|
|
789
1002
|
def constructor_types
|
@@ -791,8 +1004,7 @@ module Dhall
|
|
791
1004
|
ctypes[k] = if type.nil?
|
792
1005
|
self
|
793
1006
|
else
|
794
|
-
var
|
795
|
-
Forall.new(var: var, type: type, body: self)
|
1007
|
+
Forall.new(var: k, type: type, body: self)
|
796
1008
|
end
|
797
1009
|
end
|
798
1010
|
end
|
@@ -805,31 +1017,28 @@ module Dhall
|
|
805
1017
|
class Union < Expression
|
806
1018
|
include(ValueSemantics.for_attributes do
|
807
1019
|
tag ::String
|
808
|
-
value
|
1020
|
+
value Expression
|
809
1021
|
alternatives UnionType
|
810
1022
|
end)
|
811
1023
|
|
812
1024
|
def self.from(alts, tag, value)
|
813
|
-
|
814
|
-
tag:
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
alternatives: alts.alternatives.reject { |alt, _| alt == tag }
|
1025
|
+
if value.nil?
|
1026
|
+
Enum.new(tag: tag, alternatives: alts.without(tag))
|
1027
|
+
else
|
1028
|
+
new(
|
1029
|
+
tag: tag,
|
1030
|
+
value: TypeAnnotation.new(value: value, type: alts[tag]),
|
1031
|
+
alternatives: alts.without(tag)
|
821
1032
|
)
|
822
|
-
|
1033
|
+
end
|
823
1034
|
end
|
824
1035
|
|
825
1036
|
def to_s
|
826
|
-
|
1037
|
+
extract.to_s
|
827
1038
|
end
|
828
1039
|
|
829
1040
|
def extract
|
830
|
-
if value.
|
831
|
-
tag.to_sym
|
832
|
-
elsif value.is_a?(TypeAnnotation)
|
1041
|
+
if value.is_a?(TypeAnnotation)
|
833
1042
|
value.value
|
834
1043
|
else
|
835
1044
|
value
|
@@ -839,12 +1048,8 @@ module Dhall
|
|
839
1048
|
def reduce(handlers)
|
840
1049
|
handlers = handlers.to_h
|
841
1050
|
handler = handlers.fetch(tag.to_sym) { handlers.fetch(tag) }
|
842
|
-
|
843
|
-
|
844
|
-
else
|
845
|
-
(handler.respond_to?(:to_proc) ? handler.to_proc : handler)
|
846
|
-
.call(extract)
|
847
|
-
end
|
1051
|
+
(handler.respond_to?(:to_proc) ? handler.to_proc : handler)
|
1052
|
+
.call(extract)
|
848
1053
|
end
|
849
1054
|
|
850
1055
|
def selection_syntax
|
@@ -857,18 +1062,14 @@ module Dhall
|
|
857
1062
|
end
|
858
1063
|
|
859
1064
|
def syntax
|
860
|
-
|
861
|
-
selection_syntax
|
862
|
-
|
863
|
-
|
864
|
-
function: selection_syntax,
|
865
|
-
argument: value.is_a?(TypeAnnotation) ? value.value : value
|
866
|
-
)
|
867
|
-
end
|
1065
|
+
Application.new(
|
1066
|
+
function: selection_syntax,
|
1067
|
+
argument: value.is_a?(TypeAnnotation) ? value.value : value
|
1068
|
+
)
|
868
1069
|
end
|
869
1070
|
|
870
1071
|
def as_json
|
871
|
-
if value.
|
1072
|
+
if value.respond_to?(:type)
|
872
1073
|
syntax.as_json
|
873
1074
|
else
|
874
1075
|
[12, tag, value&.as_json, alternatives.as_json.last]
|
@@ -876,11 +1077,36 @@ module Dhall
|
|
876
1077
|
end
|
877
1078
|
end
|
878
1079
|
|
1080
|
+
class Enum < Union
|
1081
|
+
include(ValueSemantics.for_attributes do
|
1082
|
+
tag ::String
|
1083
|
+
alternatives UnionType
|
1084
|
+
end)
|
1085
|
+
|
1086
|
+
def reduce(handlers)
|
1087
|
+
handlers = handlers.to_h
|
1088
|
+
handler = handlers.fetch(tag.to_sym) { handlers.fetch(tag) }
|
1089
|
+
handler
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
def to_s
|
1093
|
+
tag
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
def extract
|
1097
|
+
tag.to_sym
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def as_json
|
1101
|
+
selection_syntax.as_json
|
1102
|
+
end
|
1103
|
+
end
|
1104
|
+
|
879
1105
|
class If < Expression
|
880
1106
|
include(ValueSemantics.for_attributes do
|
881
1107
|
predicate Expression
|
882
|
-
|
883
|
-
|
1108
|
+
def_attr :then, Expression
|
1109
|
+
def_attr :else, Expression
|
884
1110
|
end)
|
885
1111
|
|
886
1112
|
def as_json
|
@@ -893,6 +1119,10 @@ module Dhall
|
|
893
1119
|
value (0..Float::INFINITY)
|
894
1120
|
end)
|
895
1121
|
|
1122
|
+
def self.as_dhall
|
1123
|
+
Builtins[:Natural]
|
1124
|
+
end
|
1125
|
+
|
896
1126
|
def coerce(other)
|
897
1127
|
[other.as_dhall, self]
|
898
1128
|
end
|
@@ -954,6 +1184,10 @@ module Dhall
|
|
954
1184
|
value ::Integer
|
955
1185
|
end)
|
956
1186
|
|
1187
|
+
def self.as_dhall
|
1188
|
+
Builtins[:Integer]
|
1189
|
+
end
|
1190
|
+
|
957
1191
|
def to_s
|
958
1192
|
"#{value >= 0 ? "+" : ""}#{value}"
|
959
1193
|
end
|
@@ -976,6 +1210,10 @@ module Dhall
|
|
976
1210
|
value ::Float
|
977
1211
|
end)
|
978
1212
|
|
1213
|
+
def self.as_dhall
|
1214
|
+
Builtins[:Double]
|
1215
|
+
end
|
1216
|
+
|
979
1217
|
def to_s
|
980
1218
|
value.to_s
|
981
1219
|
end
|
@@ -1030,12 +1268,16 @@ module Dhall
|
|
1030
1268
|
value ::String, coerce: ->(s) { s.encode("UTF-8") }
|
1031
1269
|
end)
|
1032
1270
|
|
1271
|
+
def self.as_dhall
|
1272
|
+
Builtins[:Text]
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
def empty?
|
1276
|
+
value.empty?
|
1277
|
+
end
|
1278
|
+
|
1033
1279
|
def <<(other)
|
1034
|
-
|
1035
|
-
with(value: value + other.value)
|
1036
|
-
else
|
1037
|
-
super
|
1038
|
-
end
|
1280
|
+
with(value: value + other.value)
|
1039
1281
|
end
|
1040
1282
|
|
1041
1283
|
def to_s
|
@@ -1068,6 +1310,14 @@ module Dhall
|
|
1068
1310
|
fixed.length == 1 ? fixed.first : new(chunks: fixed)
|
1069
1311
|
end
|
1070
1312
|
|
1313
|
+
def start_empty?
|
1314
|
+
chunks.first.empty?
|
1315
|
+
end
|
1316
|
+
|
1317
|
+
def end_empty?
|
1318
|
+
chunks.last.empty?
|
1319
|
+
end
|
1320
|
+
|
1071
1321
|
def as_json
|
1072
1322
|
[18, *chunks.map { |chunk| chunk.is_a?(Text) ? chunk.value : chunk.as_json }]
|
1073
1323
|
end
|
@@ -1076,89 +1326,90 @@ module Dhall
|
|
1076
1326
|
class Import < Expression
|
1077
1327
|
class IntegrityCheck
|
1078
1328
|
include(ValueSemantics.for_attributes do
|
1079
|
-
|
1080
|
-
|
1329
|
+
code ::Integer
|
1330
|
+
digest ::String
|
1081
1331
|
end)
|
1082
1332
|
|
1083
1333
|
class FailureException < StandardError; end
|
1084
1334
|
|
1085
|
-
def
|
1086
|
-
|
1087
|
-
protocol: protocol,
|
1088
|
-
data: data
|
1089
|
-
)
|
1335
|
+
def to_s
|
1336
|
+
"#{Multihashes::TABLE[code].sub(/\Asha2-/, "sha")}:#{hexdigest}"
|
1090
1337
|
end
|
1091
1338
|
|
1092
|
-
def
|
1093
|
-
"
|
1339
|
+
def hexdigest
|
1340
|
+
digest.unpack("H*").first.encode(Encoding::UTF_8)
|
1094
1341
|
end
|
1095
1342
|
|
1096
|
-
def
|
1097
|
-
|
1343
|
+
def ipfs
|
1344
|
+
"/ipfs/b#{Base32.encode("\x01\x55" + as_json).downcase.sub(/=*$/, "")}"
|
1345
|
+
end
|
1098
1346
|
|
1347
|
+
def check(expr)
|
1099
1348
|
expr = expr.normalize
|
1100
1349
|
return expr if expr.cache_key == to_s
|
1101
1350
|
|
1102
|
-
raise FailureException, "#{expr}
|
1351
|
+
raise FailureException, "#{expr} hash #{expr.cache_key}" \
|
1352
|
+
" does not match #{self}"
|
1103
1353
|
end
|
1104
1354
|
|
1105
1355
|
def as_json
|
1106
|
-
|
1356
|
+
Multihashes.encode(digest, Multihashes::TABLE[code])
|
1107
1357
|
end
|
1108
1358
|
end
|
1109
1359
|
|
1110
|
-
class
|
1111
|
-
|
1112
|
-
headers Either(nil, Expression)
|
1113
|
-
authority ::String
|
1114
|
-
path ArrayOf(::String)
|
1115
|
-
query Either(nil, ::String)
|
1116
|
-
end)
|
1360
|
+
class NoIntegrityCheck < IntegrityCheck
|
1361
|
+
def initialize; end
|
1117
1362
|
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
"value" => Variable["Text"]
|
1122
|
-
}
|
1123
|
-
)
|
1363
|
+
def to_s
|
1364
|
+
""
|
1365
|
+
end
|
1124
1366
|
|
1125
|
-
def
|
1126
|
-
|
1127
|
-
|
1128
|
-
|
1129
|
-
path: path,
|
1130
|
-
query: query,
|
1131
|
-
)
|
1367
|
+
def hexdigest; end
|
1368
|
+
|
1369
|
+
def check(expr)
|
1370
|
+
expr.normalize
|
1132
1371
|
end
|
1133
1372
|
|
1134
|
-
def
|
1135
|
-
|
1136
|
-
hash.fetch(:headers, headers),
|
1137
|
-
hash.fetch(:authority, authority),
|
1138
|
-
*hash.fetch(:path, path),
|
1139
|
-
hash.fetch(:query, query)
|
1140
|
-
)
|
1373
|
+
def as_json
|
1374
|
+
nil
|
1141
1375
|
end
|
1376
|
+
end
|
1142
1377
|
|
1143
|
-
|
1144
|
-
|
1145
|
-
|
1146
|
-
"
|
1147
|
-
|
1148
|
-
|
1149
|
-
nil
|
1150
|
-
|
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
|
1151
1402
|
end
|
1152
1403
|
|
1153
1404
|
def headers
|
1154
|
-
|
1155
|
-
|
1405
|
+
header_type = RecordType.new(
|
1406
|
+
record: {
|
1407
|
+
"mapKey" => Builtins[:Text],
|
1408
|
+
"mapValue" => Builtins[:Text]
|
1409
|
+
}
|
1410
|
+
)
|
1156
1411
|
|
1157
|
-
|
1158
|
-
escaped_path = path.map do |c|
|
1159
|
-
::URI.encode_www_form_component(c).gsub("+", "%20")
|
1160
|
-
end
|
1161
|
-
URI("#{scheme}://#{authority}/#{escaped_path.join("/")}?#{query}")
|
1412
|
+
super || EmptyList.new(element_type: header_type)
|
1162
1413
|
end
|
1163
1414
|
|
1164
1415
|
def chain_onto(relative_to)
|
@@ -1171,23 +1422,43 @@ module Dhall
|
|
1171
1422
|
|
1172
1423
|
def canonical
|
1173
1424
|
with(
|
1174
|
-
path: (path[1..-1] + [""])
|
1175
|
-
.reduce([[], path.first]) { |(pth, prev), c|
|
1425
|
+
path: (path[1..-1] + [""]).reduce([[], path.first]) { |(pth, prev), c|
|
1176
1426
|
c == ".." ? [pth, prev] : [pth + [prev], c]
|
1177
1427
|
}.first.reject { |c| c == "." }
|
1178
1428
|
)
|
1179
1429
|
end
|
1180
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
|
+
|
1181
1442
|
def origin
|
1182
|
-
"#{scheme}://#{authority}"
|
1443
|
+
"#{uri.scheme}://#{authority}"
|
1183
1444
|
end
|
1184
1445
|
|
1185
1446
|
def to_s
|
1186
1447
|
uri.to_s
|
1187
1448
|
end
|
1188
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
|
+
|
1189
1460
|
def as_json
|
1190
|
-
[@headers&.as_json, authority, *path, query]
|
1461
|
+
[@headers&.as_json, authority, *path, uri.query]
|
1191
1462
|
end
|
1192
1463
|
end
|
1193
1464
|
|
@@ -1195,20 +1466,12 @@ module Dhall
|
|
1195
1466
|
def resolve(resolver)
|
1196
1467
|
resolver.resolve_http(self)
|
1197
1468
|
end
|
1198
|
-
|
1199
|
-
def scheme
|
1200
|
-
"http"
|
1201
|
-
end
|
1202
1469
|
end
|
1203
1470
|
|
1204
1471
|
class Https < URI
|
1205
1472
|
def resolve(resolver)
|
1206
1473
|
resolver.resolve_https(self)
|
1207
1474
|
end
|
1208
|
-
|
1209
|
-
def scheme
|
1210
|
-
"https"
|
1211
|
-
end
|
1212
1475
|
end
|
1213
1476
|
|
1214
1477
|
class Path
|
@@ -1225,13 +1488,15 @@ module Dhall
|
|
1225
1488
|
end
|
1226
1489
|
|
1227
1490
|
def self.from_string(s)
|
1228
|
-
|
1229
|
-
if
|
1230
|
-
AbsolutePath.new(*
|
1231
|
-
elsif
|
1232
|
-
RelativeToHomePath.new(*
|
1491
|
+
prefix, *suffix = s.to_s.split(/\//)
|
1492
|
+
if prefix == ""
|
1493
|
+
AbsolutePath.new(*suffix)
|
1494
|
+
elsif prefix == "~"
|
1495
|
+
RelativeToHomePath.new(*suffix)
|
1496
|
+
elsif prefix == ".."
|
1497
|
+
RelativeToParentPath.new(*suffix)
|
1233
1498
|
else
|
1234
|
-
RelativePath.new(*
|
1499
|
+
RelativePath.new(prefix, *suffix)
|
1235
1500
|
end
|
1236
1501
|
end
|
1237
1502
|
|
@@ -1251,6 +1516,10 @@ module Dhall
|
|
1251
1516
|
pathname.to_s
|
1252
1517
|
end
|
1253
1518
|
|
1519
|
+
def location
|
1520
|
+
Union.from(Location, "Local", to_s.as_dhall)
|
1521
|
+
end
|
1522
|
+
|
1254
1523
|
def as_json
|
1255
1524
|
path
|
1256
1525
|
end
|
@@ -1261,8 +1530,8 @@ module Dhall
|
|
1261
1530
|
Pathname.new("/").join(*path)
|
1262
1531
|
end
|
1263
1532
|
|
1264
|
-
def to_uri(scheme,
|
1265
|
-
scheme.new(
|
1533
|
+
def to_uri(scheme, base_uri)
|
1534
|
+
scheme.new(uri: base_uri + Util.path_components_to_uri(*path))
|
1266
1535
|
end
|
1267
1536
|
|
1268
1537
|
def chain_onto(relative_to)
|
@@ -1279,6 +1548,10 @@ module Dhall
|
|
1279
1548
|
Pathname.new(".").join(*path)
|
1280
1549
|
end
|
1281
1550
|
|
1551
|
+
def to_s
|
1552
|
+
"./#{pathname}"
|
1553
|
+
end
|
1554
|
+
|
1282
1555
|
def chain_onto(relative_to)
|
1283
1556
|
relative_to.with(
|
1284
1557
|
path: relative_to.path[0..-2] + path
|
@@ -1303,7 +1576,7 @@ module Dhall
|
|
1303
1576
|
Pathname.new("~").join(*@path)
|
1304
1577
|
end
|
1305
1578
|
|
1306
|
-
def chain_onto(
|
1579
|
+
def chain_onto(relative_to)
|
1307
1580
|
if relative_to.is_a?(URI)
|
1308
1581
|
raise ImportBannedException, "remote import cannot import #{self}"
|
1309
1582
|
end
|
@@ -1313,23 +1586,7 @@ module Dhall
|
|
1313
1586
|
end
|
1314
1587
|
|
1315
1588
|
class EnvironmentVariable
|
1316
|
-
|
1317
|
-
"\"" => "\"",
|
1318
|
-
"\\" => "\\",
|
1319
|
-
"a" => "\a",
|
1320
|
-
"b" => "\b",
|
1321
|
-
"f" => "\f",
|
1322
|
-
"n" => "\n",
|
1323
|
-
"r" => "\r",
|
1324
|
-
"t" => "\t",
|
1325
|
-
"v" => "\v"
|
1326
|
-
}.freeze
|
1327
|
-
|
1328
|
-
def self.decode(var)
|
1329
|
-
var.gsub(/\\[\"\\abfnrtv]/) do |escape|
|
1330
|
-
ESCAPES.fetch(escape[1])
|
1331
|
-
end
|
1332
|
-
end
|
1589
|
+
attr_reader :var
|
1333
1590
|
|
1334
1591
|
def initialize(var)
|
1335
1592
|
@var = var
|
@@ -1340,28 +1597,27 @@ module Dhall
|
|
1340
1597
|
raise ImportBannedException, "remote import cannot import #{self}"
|
1341
1598
|
end
|
1342
1599
|
|
1343
|
-
|
1600
|
+
self
|
1601
|
+
end
|
1602
|
+
|
1603
|
+
def path
|
1604
|
+
[]
|
1605
|
+
end
|
1606
|
+
|
1607
|
+
def with(path:)
|
1608
|
+
Path.from_string(path.join("/"))
|
1344
1609
|
end
|
1345
1610
|
|
1346
1611
|
def canonical
|
1347
|
-
|
1612
|
+
self
|
1348
1613
|
end
|
1349
1614
|
|
1350
1615
|
def real_path
|
1351
|
-
|
1352
|
-
raise ImportFailedException, "No #{self}"
|
1353
|
-
end
|
1354
|
-
if val =~ /\Ahttps?:\/\//
|
1355
|
-
URI.from_uri(URI(val))
|
1356
|
-
else
|
1357
|
-
Path.from_string(val)
|
1358
|
-
end
|
1616
|
+
self
|
1359
1617
|
end
|
1360
1618
|
|
1361
1619
|
def resolve(resolver)
|
1362
|
-
|
1363
|
-
real_path.resolve(resolver)
|
1364
|
-
end
|
1620
|
+
resolver.resolve_environment(self)
|
1365
1621
|
end
|
1366
1622
|
|
1367
1623
|
def origin
|
@@ -1369,13 +1625,27 @@ module Dhall
|
|
1369
1625
|
end
|
1370
1626
|
|
1371
1627
|
def to_s
|
1372
|
-
|
1628
|
+
escapes = Parser::PosixEnvironmentVariableCharacter::ESCAPES
|
1629
|
+
"env:#{@var.gsub(/[\"\\\a\b\f\n\r\t\v]/) do |c|
|
1630
|
+
"\\" + escapes.find { |(_, v)| v == c }.first
|
1631
|
+
end}"
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
def location
|
1635
|
+
Union.from(Location, "Environment", to_s.as_dhall)
|
1373
1636
|
end
|
1374
1637
|
|
1638
|
+
def hash
|
1639
|
+
@var.hash
|
1640
|
+
end
|
1641
|
+
|
1642
|
+
def eql?(other)
|
1643
|
+
other.is_a?(self.class) && other.var == var
|
1644
|
+
end
|
1645
|
+
alias == eql?
|
1646
|
+
|
1375
1647
|
def as_json
|
1376
|
-
@var
|
1377
|
-
"\\" + ESCAPES.find { |(_, v)| v == c }.first
|
1378
|
-
end
|
1648
|
+
@var
|
1379
1649
|
end
|
1380
1650
|
end
|
1381
1651
|
|
@@ -1398,26 +1668,44 @@ module Dhall
|
|
1398
1668
|
"missing"
|
1399
1669
|
end
|
1400
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
|
+
|
1401
1680
|
def as_json
|
1402
1681
|
[]
|
1403
1682
|
end
|
1404
1683
|
end
|
1405
1684
|
|
1406
1685
|
class Expression
|
1407
|
-
def self.call(import_value)
|
1408
|
-
|
1686
|
+
def self.call(import_value, deadline: Util::NoDeadline.new)
|
1687
|
+
return import_value if import_value.is_a?(Dhall::Expression)
|
1688
|
+
|
1689
|
+
Dhall.load_raw(import_value, timeout: deadline.timeout)
|
1409
1690
|
end
|
1410
1691
|
end
|
1411
1692
|
|
1412
1693
|
class Text
|
1413
|
-
def self.call(import_value)
|
1694
|
+
def self.call(import_value, deadline: Util::NoDeadline.new)
|
1414
1695
|
Dhall::Text.new(value: import_value)
|
1415
1696
|
end
|
1416
1697
|
end
|
1417
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
|
+
|
1418
1705
|
IMPORT_TYPES = [
|
1419
1706
|
Expression,
|
1420
|
-
Text
|
1707
|
+
Text,
|
1708
|
+
AsLocation
|
1421
1709
|
].freeze
|
1422
1710
|
|
1423
1711
|
PATH_TYPES = [
|
@@ -1427,14 +1715,14 @@ module Dhall
|
|
1427
1715
|
].freeze
|
1428
1716
|
|
1429
1717
|
include(ValueSemantics.for_attributes do
|
1430
|
-
integrity_check IntegrityCheck, default:
|
1718
|
+
integrity_check IntegrityCheck, default: NoIntegrityCheck.new
|
1431
1719
|
import_type Class
|
1432
1720
|
path Either(*PATH_TYPES)
|
1433
1721
|
end)
|
1434
1722
|
|
1435
1723
|
def initialize(integrity_check, import_type, path)
|
1436
1724
|
super(
|
1437
|
-
integrity_check: integrity_check ||
|
1725
|
+
integrity_check: integrity_check || NoIntegrityCheck.new,
|
1438
1726
|
import_type: import_type,
|
1439
1727
|
path: path
|
1440
1728
|
)
|
@@ -1452,15 +1740,18 @@ module Dhall
|
|
1452
1740
|
path.chain_onto(relative_to).canonical
|
1453
1741
|
end
|
1454
1742
|
|
1455
|
-
def
|
1456
|
-
|
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
|
1457
1747
|
end
|
1458
1748
|
|
1459
1749
|
def cache_key(relative_to)
|
1460
|
-
|
1461
|
-
|
1750
|
+
key = integrity_check.to_s
|
1751
|
+
if key.empty?
|
1752
|
+
real_path(relative_to)
|
1462
1753
|
else
|
1463
|
-
|
1754
|
+
key
|
1464
1755
|
end
|
1465
1756
|
end
|
1466
1757
|
|
@@ -1477,7 +1768,7 @@ module Dhall
|
|
1477
1768
|
|
1478
1769
|
class Let < Expression
|
1479
1770
|
include(ValueSemantics.for_attributes do
|
1480
|
-
var
|
1771
|
+
var ::String
|
1481
1772
|
assign Expression
|
1482
1773
|
type Either(nil, Expression)
|
1483
1774
|
end)
|
@@ -1493,6 +1784,19 @@ module Dhall
|
|
1493
1784
|
body Expression
|
1494
1785
|
end)
|
1495
1786
|
|
1787
|
+
def lets
|
1788
|
+
[let]
|
1789
|
+
end
|
1790
|
+
|
1791
|
+
def flatten
|
1792
|
+
flattened = body.is_a?(LetIn) ? body.flatten : body
|
1793
|
+
if flattened.is_a?(LetBlock)
|
1794
|
+
LetBlock.new(lets: lets + flattened.lets, body: flattened.body)
|
1795
|
+
else
|
1796
|
+
LetBlock.new(lets: lets, body: body)
|
1797
|
+
end
|
1798
|
+
end
|
1799
|
+
|
1496
1800
|
def desugar
|
1497
1801
|
Application.new(
|
1498
1802
|
function: Function.new(
|
@@ -1512,24 +1816,16 @@ module Dhall
|
|
1512
1816
|
end
|
1513
1817
|
|
1514
1818
|
def as_json
|
1515
|
-
|
1819
|
+
flatten.as_json
|
1516
1820
|
end
|
1517
1821
|
end
|
1518
1822
|
|
1519
|
-
class LetBlock
|
1823
|
+
class LetBlock
|
1520
1824
|
include(ValueSemantics.for_attributes do
|
1521
|
-
lets Util::ArrayOf.new(Let
|
1825
|
+
lets Util::ArrayOf.new(Let)
|
1522
1826
|
body Expression
|
1523
1827
|
end)
|
1524
1828
|
|
1525
|
-
def self.for(lets:, body:)
|
1526
|
-
if lets.length == 1
|
1527
|
-
LetIn.new(let: lets.first, body: body)
|
1528
|
-
else
|
1529
|
-
new(lets: lets, body: body)
|
1530
|
-
end
|
1531
|
-
end
|
1532
|
-
|
1533
1829
|
def unflatten
|
1534
1830
|
lets.reverse.reduce(body) do |inside, let|
|
1535
1831
|
letin = LetIn.new(let: let, body: inside)
|
@@ -1537,10 +1833,6 @@ module Dhall
|
|
1537
1833
|
end
|
1538
1834
|
end
|
1539
1835
|
|
1540
|
-
def desugar
|
1541
|
-
unflatten(&:desugar)
|
1542
|
-
end
|
1543
|
-
|
1544
1836
|
def as_json
|
1545
1837
|
[25, *lets.flat_map(&:as_json), body.as_json]
|
1546
1838
|
end
|
@@ -1556,4 +1848,14 @@ module Dhall
|
|
1556
1848
|
[26, value.as_json, type.as_json]
|
1557
1849
|
end
|
1558
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
|
1559
1861
|
end
|