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