dhall 0.2.0 → 0.3.0
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 +4 -4
- data/README.md +1 -1
- data/bin/dhall-compile +77 -0
- data/lib/dhall/as_dhall.rb +90 -21
- data/lib/dhall/ast.rb +145 -60
- data/lib/dhall/binary.rb +9 -6
- data/lib/dhall/coder.rb +11 -6
- data/lib/dhall/normalize.rb +40 -3
- data/lib/dhall/parser.citrus +4 -4
- data/lib/dhall/parser.rb +20 -9
- data/lib/dhall/typecheck.rb +30 -2
- data/lib/dhall/util.rb +4 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 30ff6e0ad066b23996b9a31b21e7f1a30b86b265
|
4
|
+
data.tar.gz: 88efb36ee05894a74df3b691d67774b8e0eea185
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff197049f1d4ceb3e1742a4e3b44491192170c4bb1e32b7aef6bbaeb643f16b828ffdee1d78eaa628a9f0dd9d5dedd0f4c796556b2e72b92ed0705a0e8306430
|
7
|
+
data.tar.gz: e92aad6b3921f4bd25ebdf8f20204b95ceec8814250ed90b5424b70a75991ca68de8bd60b0c2cf982541c560f9e1ba135f87f0b05f685d767588150b051c465f
|
data/README.md
CHANGED
data/bin/dhall-compile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "dhall"
|
5
|
+
require "optparse"
|
6
|
+
|
7
|
+
@extension = ".dhallb"
|
8
|
+
|
9
|
+
def compile(source)
|
10
|
+
Dhall.load(
|
11
|
+
source,
|
12
|
+
timeout: Float::INFINITY,
|
13
|
+
resolver: Dhall::Resolvers::Default.new(
|
14
|
+
max_depth: Float::INFINITY
|
15
|
+
)
|
16
|
+
).then(&:to_binary)
|
17
|
+
end
|
18
|
+
|
19
|
+
def compile_file(file_path, relative_to: Pathname.new("."))
|
20
|
+
out = file_path.sub_ext(@extension)
|
21
|
+
if @output_directory
|
22
|
+
out = @output_directory + out.relative_path_from(relative_to)
|
23
|
+
out.dirname.mkpath
|
24
|
+
end
|
25
|
+
warn "#{file_path} => #{out}"
|
26
|
+
compile(file_path.expand_path).then(&out.method(:write))
|
27
|
+
end
|
28
|
+
|
29
|
+
opt_parser = OptionParser.new do |opts|
|
30
|
+
opts.banner = "Usage: dhall-compile [options] [-] [files_and_dirs]"
|
31
|
+
|
32
|
+
opts.on(
|
33
|
+
"-oDIRECTORY",
|
34
|
+
"--output-directory DIRECTORY",
|
35
|
+
"Write output to this directory"
|
36
|
+
) do |dir|
|
37
|
+
@output_directory = Pathname.new(dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on(
|
41
|
+
"-e [EXTENSION]",
|
42
|
+
"--extension [EXTENSION]",
|
43
|
+
"Use this extension for files (default .dhallb)"
|
44
|
+
) do |ext|
|
45
|
+
@extension = ext ? ".#{ext}" : ""
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.on("-h", "--help", "Show this usage information") do
|
49
|
+
warn opts
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
opt_parser.parse!
|
55
|
+
|
56
|
+
if ARGV.empty?
|
57
|
+
warn opt_parser
|
58
|
+
exit 0
|
59
|
+
end
|
60
|
+
|
61
|
+
ARGV.map(&Pathname.method(:new)).each do |path|
|
62
|
+
if !path.exist? && path.to_s == "-"
|
63
|
+
warn "Compiling STDIN to STDOUT"
|
64
|
+
compile(STDIN.read).then(&STDOUT.method(:write)).sync
|
65
|
+
elsif path.file?
|
66
|
+
compile_file(path, relative_to: path.dirname).sync
|
67
|
+
elsif path.directory?
|
68
|
+
warn "Recursively compiling #{path}"
|
69
|
+
path.find.flat_map do |child|
|
70
|
+
next if !child.file? || child.extname == ".dhallb"
|
71
|
+
compile_file(child, relative_to: path).sync
|
72
|
+
end
|
73
|
+
else
|
74
|
+
warn "#{path} may not exist"
|
75
|
+
exit 1
|
76
|
+
end
|
77
|
+
end
|
data/lib/dhall/as_dhall.rb
CHANGED
@@ -6,31 +6,84 @@ require "psych"
|
|
6
6
|
module Dhall
|
7
7
|
module AsDhall
|
8
8
|
TAGS = {
|
9
|
-
::
|
9
|
+
::Array => "List",
|
10
10
|
::FalseClass => "Bool",
|
11
|
-
::Integer => "Integer",
|
12
11
|
::Float => "Double",
|
12
|
+
::Hash => "Record",
|
13
|
+
::Integer => "Integer",
|
14
|
+
::Integer => "Integer",
|
13
15
|
::NilClass => "None",
|
14
16
|
::String => "Text",
|
15
17
|
::TrueClass => "Bool"
|
16
18
|
}.freeze
|
17
19
|
|
18
|
-
def self.tag_for(o
|
20
|
+
def self.tag_for(o)
|
19
21
|
return "Natural" if o.is_a?(::Integer) && !o.negative?
|
20
22
|
|
21
23
|
TAGS.fetch(o.class) do
|
22
|
-
|
24
|
+
o.class.name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class AnnotatedExpressionList
|
29
|
+
attr_reader :type
|
30
|
+
attr_reader :exprs
|
31
|
+
|
32
|
+
def self.from(type_annotation)
|
33
|
+
if type_annotation.nil?
|
34
|
+
new(nil, [nil])
|
35
|
+
else
|
36
|
+
new(type_annotation.type, [type_annotation.value])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(type, exprs)
|
41
|
+
@type = type
|
42
|
+
@exprs = exprs
|
43
|
+
end
|
44
|
+
|
45
|
+
def +(other)
|
46
|
+
raise "#{type} != #{other.type}" if type != other.type
|
47
|
+
self.class.new(type, exprs + other.exprs)
|
23
48
|
end
|
24
49
|
end
|
25
50
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
51
|
+
class UnionInferer
|
52
|
+
def initialize(tagged={})
|
53
|
+
@tagged = tagged
|
54
|
+
end
|
55
|
+
|
56
|
+
def union_type
|
57
|
+
UnionType.new(alternatives: Hash[@tagged.map { |k, v| [k, v.type] }])
|
58
|
+
end
|
59
|
+
|
60
|
+
def union_for(expr)
|
61
|
+
if expr.is_a?(Enum)
|
62
|
+
tag = expr.tag
|
63
|
+
expr = nil
|
64
|
+
else
|
65
|
+
tag = @tagged.keys.find { |k| @tagged[k].exprs.include?(expr) }
|
66
|
+
end
|
67
|
+
expr = expr.extract if expr.is_a?(Union)
|
68
|
+
Union.from(union_type, tag, expr)
|
69
|
+
end
|
70
|
+
|
71
|
+
def with(tag, type_annotation)
|
72
|
+
anno = AnnotatedExpressionList.from(type_annotation)
|
73
|
+
if @tagged.key?(tag) && @tagged[tag].type != anno.type
|
74
|
+
disambiguate_against(tag, anno)
|
75
|
+
else
|
76
|
+
self.class.new(@tagged.merge(tag => anno) { |_, x, y| x + y })
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def disambiguate_against(tag, anno)
|
81
|
+
self.class.new(
|
82
|
+
@tagged.reject { |k, _| k == tag }.merge(
|
83
|
+
"#{tag}_#{@tagged[tag].type.digest.hexdigest}" => @tagged[tag],
|
84
|
+
"#{tag}_#{anno.type.digest.hexdigest}" => anno
|
85
|
+
)
|
86
|
+
)
|
34
87
|
end
|
35
88
|
end
|
36
89
|
|
@@ -46,9 +99,8 @@ module Dhall
|
|
46
99
|
|
47
100
|
refine ::Symbol do
|
48
101
|
def as_dhall
|
49
|
-
Dhall::
|
102
|
+
Dhall::Enum.new(
|
50
103
|
tag: to_s,
|
51
|
-
value: nil,
|
52
104
|
alternatives: Dhall::UnionType.new(alternatives: {})
|
53
105
|
)
|
54
106
|
end
|
@@ -143,17 +195,28 @@ module Dhall
|
|
143
195
|
|
144
196
|
class Union
|
145
197
|
def initialize(values, exprs, types)
|
146
|
-
@
|
198
|
+
@tags, @types = values.zip(types).map { |(value, type)|
|
199
|
+
if type.is_a?(UnionType) && type.alternatives.length == 1
|
200
|
+
type.alternatives.to_a.first
|
201
|
+
else
|
202
|
+
[AsDhall.tag_for(value), type]
|
203
|
+
end
|
204
|
+
}.transpose
|
147
205
|
@exprs = exprs
|
148
|
-
@
|
206
|
+
@inferer = UnionInferer.new
|
149
207
|
end
|
150
208
|
|
151
209
|
def list
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
210
|
+
final_inferer =
|
211
|
+
@tags
|
212
|
+
.zip(@exprs, @types)
|
213
|
+
.reduce(@inferer) do |inferer, (tag, expr, type)|
|
214
|
+
inferer.with(
|
215
|
+
tag,
|
216
|
+
type.nil? ? nil : TypeAnnotation.new(value: expr, type: type)
|
217
|
+
)
|
218
|
+
end
|
219
|
+
List.new(elements: @exprs.map(&final_inferer.method(:union_for)))
|
157
220
|
end
|
158
221
|
end
|
159
222
|
end
|
@@ -215,5 +278,11 @@ module Dhall
|
|
215
278
|
)
|
216
279
|
end
|
217
280
|
end
|
281
|
+
|
282
|
+
refine ::Proc do
|
283
|
+
def as_dhall
|
284
|
+
FunctionProxy.new(self)
|
285
|
+
end
|
286
|
+
end
|
218
287
|
end
|
219
288
|
end
|
data/lib/dhall/ast.rb
CHANGED
@@ -102,6 +102,10 @@ module Dhall
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
def to_s
|
106
|
+
inspect
|
107
|
+
end
|
108
|
+
|
105
109
|
def as_dhall
|
106
110
|
self
|
107
111
|
end
|
@@ -157,7 +161,8 @@ module Dhall
|
|
157
161
|
end
|
158
162
|
end
|
159
163
|
|
160
|
-
def call(*args)
|
164
|
+
def call(*args, &block)
|
165
|
+
args += [block] if block
|
161
166
|
args.map! { |arg| arg&.as_dhall }
|
162
167
|
return super if args.length > 1
|
163
168
|
|
@@ -168,6 +173,29 @@ module Dhall
|
|
168
173
|
end
|
169
174
|
|
170
175
|
alias [] call
|
176
|
+
alias === call
|
177
|
+
|
178
|
+
def <<(other)
|
179
|
+
FunctionProxy.new(
|
180
|
+
->(*args, &block) { call(other.call(*args, &block)) },
|
181
|
+
curry: false
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
def >>(other)
|
186
|
+
FunctionProxy.new(
|
187
|
+
->(*args, &block) { other.call(call(*args, &block)) },
|
188
|
+
curry: false
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
def binding
|
193
|
+
to_proc.binding
|
194
|
+
end
|
195
|
+
|
196
|
+
def curry
|
197
|
+
self
|
198
|
+
end
|
171
199
|
|
172
200
|
def as_json
|
173
201
|
if var == "_"
|
@@ -188,6 +216,28 @@ module Dhall
|
|
188
216
|
end
|
189
217
|
end
|
190
218
|
|
219
|
+
class FunctionProxy < Function
|
220
|
+
def initialize(callable, curry: true)
|
221
|
+
@callable = if !curry
|
222
|
+
callable
|
223
|
+
elsif callable.respond_to?(:curry)
|
224
|
+
callable.curry
|
225
|
+
elsif callable.respond_to?(:to_proc)
|
226
|
+
callable.to_proc.curry
|
227
|
+
else
|
228
|
+
callable.method(:call).to_proc.curry
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def call(*args, &block)
|
233
|
+
@callable.call(*args.map { |arg| arg&.as_dhall }, &block).as_dhall
|
234
|
+
end
|
235
|
+
|
236
|
+
def as_json
|
237
|
+
raise "Cannot serialize #{self}"
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
191
241
|
class Bool < Expression
|
192
242
|
include(ValueSemantics.for_attributes do
|
193
243
|
value Bool()
|
@@ -764,9 +814,22 @@ module Dhall
|
|
764
814
|
|
765
815
|
class UnionType < Expression
|
766
816
|
include(ValueSemantics.for_attributes do
|
767
|
-
alternatives Util::HashOf.new(::String, Either(Expression, nil))
|
817
|
+
alternatives Util::HashOf.new(::String, Either(Expression, nil)), default: {}
|
768
818
|
end)
|
769
819
|
|
820
|
+
def empty?
|
821
|
+
alternatives.empty?
|
822
|
+
end
|
823
|
+
|
824
|
+
def [](k)
|
825
|
+
alternatives.fetch(k)
|
826
|
+
end
|
827
|
+
|
828
|
+
def without(*keys)
|
829
|
+
keys.map!(&:to_s)
|
830
|
+
with(alternatives: alternatives.reject { |k, _| keys.include?(k) })
|
831
|
+
end
|
832
|
+
|
770
833
|
def record
|
771
834
|
alternatives
|
772
835
|
end
|
@@ -779,8 +842,8 @@ module Dhall
|
|
779
842
|
self == other
|
780
843
|
end
|
781
844
|
|
782
|
-
def merge(other)
|
783
|
-
with(alternatives: alternatives.merge(other.alternatives))
|
845
|
+
def merge(other, &block)
|
846
|
+
with(alternatives: alternatives.merge(other.alternatives, &block))
|
784
847
|
end
|
785
848
|
|
786
849
|
def fetch(k, default=nil)
|
@@ -817,31 +880,28 @@ module Dhall
|
|
817
880
|
class Union < Expression
|
818
881
|
include(ValueSemantics.for_attributes do
|
819
882
|
tag ::String
|
820
|
-
value
|
883
|
+
value Expression
|
821
884
|
alternatives UnionType
|
822
885
|
end)
|
823
886
|
|
824
887
|
def self.from(alts, tag, value)
|
825
|
-
|
826
|
-
tag:
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
alternatives: alts.alternatives.reject { |alt, _| alt == tag }
|
888
|
+
if value.nil?
|
889
|
+
Enum.new(tag: tag, alternatives: alts.without(tag))
|
890
|
+
else
|
891
|
+
new(
|
892
|
+
tag: tag,
|
893
|
+
value: TypeAnnotation.new(value: value, type: alts[tag]),
|
894
|
+
alternatives: alts.without(tag)
|
833
895
|
)
|
834
|
-
|
896
|
+
end
|
835
897
|
end
|
836
898
|
|
837
899
|
def to_s
|
838
|
-
|
900
|
+
extract.to_s
|
839
901
|
end
|
840
902
|
|
841
903
|
def extract
|
842
|
-
if value.
|
843
|
-
tag.to_sym
|
844
|
-
elsif value.is_a?(TypeAnnotation)
|
904
|
+
if value.is_a?(TypeAnnotation)
|
845
905
|
value.value
|
846
906
|
else
|
847
907
|
value
|
@@ -851,12 +911,8 @@ module Dhall
|
|
851
911
|
def reduce(handlers)
|
852
912
|
handlers = handlers.to_h
|
853
913
|
handler = handlers.fetch(tag.to_sym) { handlers.fetch(tag) }
|
854
|
-
|
855
|
-
|
856
|
-
else
|
857
|
-
(handler.respond_to?(:to_proc) ? handler.to_proc : handler)
|
858
|
-
.call(extract)
|
859
|
-
end
|
914
|
+
(handler.respond_to?(:to_proc) ? handler.to_proc : handler)
|
915
|
+
.call(extract)
|
860
916
|
end
|
861
917
|
|
862
918
|
def selection_syntax
|
@@ -869,18 +925,14 @@ module Dhall
|
|
869
925
|
end
|
870
926
|
|
871
927
|
def syntax
|
872
|
-
|
873
|
-
selection_syntax
|
874
|
-
|
875
|
-
|
876
|
-
function: selection_syntax,
|
877
|
-
argument: value.is_a?(TypeAnnotation) ? value.value : value
|
878
|
-
)
|
879
|
-
end
|
928
|
+
Application.new(
|
929
|
+
function: selection_syntax,
|
930
|
+
argument: value.is_a?(TypeAnnotation) ? value.value : value
|
931
|
+
)
|
880
932
|
end
|
881
933
|
|
882
934
|
def as_json
|
883
|
-
if value.
|
935
|
+
if value.respond_to?(:type)
|
884
936
|
syntax.as_json
|
885
937
|
else
|
886
938
|
[12, tag, value&.as_json, alternatives.as_json.last]
|
@@ -888,6 +940,31 @@ module Dhall
|
|
888
940
|
end
|
889
941
|
end
|
890
942
|
|
943
|
+
class Enum < Union
|
944
|
+
include(ValueSemantics.for_attributes do
|
945
|
+
tag ::String
|
946
|
+
alternatives UnionType
|
947
|
+
end)
|
948
|
+
|
949
|
+
def reduce(handlers)
|
950
|
+
handlers = handlers.to_h
|
951
|
+
handler = handlers.fetch(tag.to_sym) { handlers.fetch(tag) }
|
952
|
+
handler
|
953
|
+
end
|
954
|
+
|
955
|
+
def to_s
|
956
|
+
tag
|
957
|
+
end
|
958
|
+
|
959
|
+
def extract
|
960
|
+
tag.to_sym
|
961
|
+
end
|
962
|
+
|
963
|
+
def as_json
|
964
|
+
selection_syntax.as_json
|
965
|
+
end
|
966
|
+
end
|
967
|
+
|
891
968
|
class If < Expression
|
892
969
|
include(ValueSemantics.for_attributes do
|
893
970
|
predicate Expression
|
@@ -1058,12 +1135,12 @@ module Dhall
|
|
1058
1135
|
Builtins[:Text]
|
1059
1136
|
end
|
1060
1137
|
|
1138
|
+
def empty?
|
1139
|
+
value.empty?
|
1140
|
+
end
|
1141
|
+
|
1061
1142
|
def <<(other)
|
1062
|
-
|
1063
|
-
with(value: value + other.value)
|
1064
|
-
else
|
1065
|
-
super
|
1066
|
-
end
|
1143
|
+
with(value: value + other.value)
|
1067
1144
|
end
|
1068
1145
|
|
1069
1146
|
def to_s
|
@@ -1096,6 +1173,14 @@ module Dhall
|
|
1096
1173
|
fixed.length == 1 ? fixed.first : new(chunks: fixed)
|
1097
1174
|
end
|
1098
1175
|
|
1176
|
+
def start_empty?
|
1177
|
+
chunks.first.empty?
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
def end_empty?
|
1181
|
+
chunks.last.empty?
|
1182
|
+
end
|
1183
|
+
|
1099
1184
|
def as_json
|
1100
1185
|
[18, *chunks.map { |chunk| chunk.is_a?(Text) ? chunk.value : chunk.as_json }]
|
1101
1186
|
end
|
@@ -1343,24 +1428,6 @@ module Dhall
|
|
1343
1428
|
end
|
1344
1429
|
|
1345
1430
|
class EnvironmentVariable
|
1346
|
-
ESCAPES = {
|
1347
|
-
"\"" => "\"",
|
1348
|
-
"\\" => "\\",
|
1349
|
-
"a" => "\a",
|
1350
|
-
"b" => "\b",
|
1351
|
-
"f" => "\f",
|
1352
|
-
"n" => "\n",
|
1353
|
-
"r" => "\r",
|
1354
|
-
"t" => "\t",
|
1355
|
-
"v" => "\v"
|
1356
|
-
}.freeze
|
1357
|
-
|
1358
|
-
def self.decode(var)
|
1359
|
-
var.gsub(/\\[\"\\abfnrtv]/) do |escape|
|
1360
|
-
ESCAPES.fetch(escape[1])
|
1361
|
-
end
|
1362
|
-
end
|
1363
|
-
|
1364
1431
|
attr_reader :var
|
1365
1432
|
|
1366
1433
|
def initialize(var)
|
@@ -1400,7 +1467,10 @@ module Dhall
|
|
1400
1467
|
end
|
1401
1468
|
|
1402
1469
|
def to_s
|
1403
|
-
|
1470
|
+
escapes = Parser::PosixEnvironmentVariableCharacter::ESCAPES
|
1471
|
+
"env:#{@var.gsub(/[\"\\\a\b\f\n\r\t\v]/) do |c|
|
1472
|
+
"\\" + escapes.find { |(_, v)| v == c }.first
|
1473
|
+
end}"
|
1404
1474
|
end
|
1405
1475
|
|
1406
1476
|
def hash
|
@@ -1413,9 +1483,7 @@ module Dhall
|
|
1413
1483
|
alias eql? ==
|
1414
1484
|
|
1415
1485
|
def as_json
|
1416
|
-
@var
|
1417
|
-
"\\" + ESCAPES.find { |(_, v)| v == c }.first
|
1418
|
-
end
|
1486
|
+
@var
|
1419
1487
|
end
|
1420
1488
|
end
|
1421
1489
|
|
@@ -1535,6 +1603,19 @@ module Dhall
|
|
1535
1603
|
body Expression
|
1536
1604
|
end)
|
1537
1605
|
|
1606
|
+
def lets
|
1607
|
+
[let]
|
1608
|
+
end
|
1609
|
+
|
1610
|
+
def flatten
|
1611
|
+
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)
|
1614
|
+
else
|
1615
|
+
self
|
1616
|
+
end
|
1617
|
+
end
|
1618
|
+
|
1538
1619
|
def desugar
|
1539
1620
|
Application.new(
|
1540
1621
|
function: Function.new(
|
@@ -1572,6 +1653,10 @@ module Dhall
|
|
1572
1653
|
end
|
1573
1654
|
end
|
1574
1655
|
|
1656
|
+
def flatten
|
1657
|
+
unflatten.flatten
|
1658
|
+
end
|
1659
|
+
|
1575
1660
|
def unflatten
|
1576
1661
|
lets.reverse.reduce(body) do |inside, let|
|
1577
1662
|
letin = LetIn.new(let: let, body: inside)
|
data/lib/dhall/binary.rb
CHANGED
@@ -192,7 +192,6 @@ module Dhall
|
|
192
192
|
class Import
|
193
193
|
def self.decode(integrity_check, import_type, path_type, *parts)
|
194
194
|
parts[0] = Dhall.decode(parts[0]) if path_type < 2 && !parts[0].nil?
|
195
|
-
parts[0] = EnvironmentVariable.decode(parts[0]) if path_type == 6
|
196
195
|
|
197
196
|
new(
|
198
197
|
IntegrityCheck.new(*integrity_check),
|
@@ -223,6 +222,13 @@ module Dhall
|
|
223
222
|
end
|
224
223
|
end
|
225
224
|
|
225
|
+
def self.handle_tag(e)
|
226
|
+
return e unless e.is_a?(::CBOR::Tagged)
|
227
|
+
return e.value if e.tag == 55799
|
228
|
+
|
229
|
+
raise "Unknown tag: #{e.inspect}"
|
230
|
+
end
|
231
|
+
|
226
232
|
BINARY = {
|
227
233
|
::TrueClass => ->(e) { Bool.new(value: e) },
|
228
234
|
::FalseClass => ->(e) { Bool.new(value: e) },
|
@@ -230,6 +236,7 @@ module Dhall
|
|
230
236
|
::String => ->(e) { Builtins[e.to_sym] || (raise "Unknown builtin") },
|
231
237
|
::Integer => ->(e) { Variable.new(index: e) },
|
232
238
|
::Array => lambda { |e|
|
239
|
+
e = e.map(&method(:handle_tag))
|
233
240
|
if e.length == 2 && e.first.is_a?(::String)
|
234
241
|
Variable.new(name: e[0], index: e[1])
|
235
242
|
else
|
@@ -238,11 +245,7 @@ module Dhall
|
|
238
245
|
(raise "Unknown expression: #{e.inspect}")
|
239
246
|
end
|
240
247
|
},
|
241
|
-
::CBOR::Tagged =>
|
242
|
-
return Dhall.decode(e.value) if e.tag == 55799
|
243
|
-
|
244
|
-
raise "Unknown tag: #{e.inspect}"
|
245
|
-
}
|
248
|
+
::CBOR::Tagged => ->(e) { Dhall.decode(handle_tag(e)) }
|
246
249
|
}.freeze
|
247
250
|
|
248
251
|
BINARY_TAGS = [
|
data/lib/dhall/coder.rb
CHANGED
@@ -117,17 +117,22 @@ module Dhall
|
|
117
117
|
|
118
118
|
refine Function do
|
119
119
|
def to_ruby(&decode)
|
120
|
-
->(*args) { decode[
|
120
|
+
->(*args) { decode[call(*args)] }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
refine Enum do
|
125
|
+
def to_ruby
|
126
|
+
extract == :None ? nil : extract
|
121
127
|
end
|
122
128
|
end
|
123
129
|
|
124
130
|
refine Union do
|
125
131
|
def to_ruby
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
nil
|
132
|
+
rtag = tag.sub(/_[0-9a-f]{64}\Z/, "")
|
133
|
+
if tag.match(/\A\p{Upper}/) &&
|
134
|
+
Object.const_defined?(rtag) && !Dhall.const_defined?(rtag, false)
|
135
|
+
yield extract, Object.const_get(rtag)
|
131
136
|
else
|
132
137
|
yield extract
|
133
138
|
end
|
data/lib/dhall/normalize.rb
CHANGED
@@ -120,9 +120,18 @@ module Dhall
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
class
|
123
|
+
class FunctionProxy
|
124
|
+
def shift(*)
|
125
|
+
self
|
126
|
+
end
|
127
|
+
|
128
|
+
def substitute(*)
|
129
|
+
raise "Cannot substitute #{self}"
|
130
|
+
end
|
124
131
|
|
125
|
-
|
132
|
+
def normalize
|
133
|
+
self
|
134
|
+
end
|
126
135
|
end
|
127
136
|
|
128
137
|
class Variable
|
@@ -335,6 +344,12 @@ module Dhall
|
|
335
344
|
end
|
336
345
|
end
|
337
346
|
|
347
|
+
class Enum
|
348
|
+
def normalize
|
349
|
+
with(alternatives: alternatives.normalize)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
338
353
|
class If
|
339
354
|
def normalize
|
340
355
|
normalized = super
|
@@ -357,7 +372,14 @@ module Dhall
|
|
357
372
|
|
358
373
|
class TextLiteral
|
359
374
|
def normalize
|
360
|
-
TextLiteral.for(*super.flatten.chunks)
|
375
|
+
lit = TextLiteral.for(*super.flatten.chunks)
|
376
|
+
|
377
|
+
if lit.is_a?(TextLiteral) && lit.chunks.length == 3 &&
|
378
|
+
lit.start_empty? && lit.end_empty?
|
379
|
+
lit.chunks[1]
|
380
|
+
else
|
381
|
+
lit
|
382
|
+
end
|
361
383
|
end
|
362
384
|
|
363
385
|
def flatten
|
@@ -380,6 +402,17 @@ module Dhall
|
|
380
402
|
body: body.shift(amount, name, min_index + 1)
|
381
403
|
)
|
382
404
|
end
|
405
|
+
|
406
|
+
def substitute(svar, with_expr)
|
407
|
+
var = let.var
|
408
|
+
with(
|
409
|
+
let: let.substitute(svar, with_expr),
|
410
|
+
body: body.substitute(
|
411
|
+
var == svar.name ? svar.with(index: svar.index + 1) : svar,
|
412
|
+
with_expr.shift(1, var, 0)
|
413
|
+
)
|
414
|
+
)
|
415
|
+
end
|
383
416
|
end
|
384
417
|
|
385
418
|
class LetBlock
|
@@ -390,6 +423,10 @@ module Dhall
|
|
390
423
|
def shift(amount, name, min_index)
|
391
424
|
unflatten.shift(amount, name, min_index)
|
392
425
|
end
|
426
|
+
|
427
|
+
def substitute(svar, with_expr)
|
428
|
+
unflatten.substitute(svar, with_expr)
|
429
|
+
end
|
393
430
|
end
|
394
431
|
|
395
432
|
class TypeAnnotation
|
data/lib/dhall/parser.citrus
CHANGED
@@ -10,10 +10,10 @@ rule block_comment
|
|
10
10
|
(/(?:\u{7b})(?:\u{2d})/i (block_comment_continue))
|
11
11
|
end
|
12
12
|
rule block_comment_char
|
13
|
-
(/[\u{20}-@\u{5b}-\u{10ffff}]/i | (tab) | (end_of_line))
|
13
|
+
!("{-" | "-}") (/[\u{20}-@\u{5b}-\u{10ffff}]/i | (tab) | (end_of_line))
|
14
14
|
end
|
15
15
|
rule block_comment_continue
|
16
|
-
(
|
16
|
+
("-}" | block_comment_char+ block_comment_continue | (block_comment block_comment_continue))
|
17
17
|
end
|
18
18
|
rule not_end_of_line
|
19
19
|
(/[\u{20}-@\u{5b}-\u{10ffff}]/i | (tab))
|
@@ -340,7 +340,7 @@ rule ipvfuture
|
|
340
340
|
(`v` ((hexdig)+) /\u{2e}/i (((unreserved) | (sub_delims) | `:`)+))
|
341
341
|
end
|
342
342
|
rule ipv6address
|
343
|
-
(((((h16) `:`) 6*6) (ls32)) | (`::` (((h16) `:`) 5*5) (ls32)) | (((h16)?) `::` (((h16) `:`) 4*4) (ls32)) | ((((
|
343
|
+
(((((h16) `:`) 6*6) (ls32)) | (`::` (((h16) `:`) 5*5) (ls32)) | (((h16)?) `::` (((h16) `:`) 4*4) (ls32)) | ((((h16) ((`:` (h16))?))?) `::` (((h16) `:`) 3*3) (ls32)) | ((((h16) ((`:` (h16)) 0*2))?) `::` (((h16) `:`) 2*2) (ls32)) | ((((h16) ((`:` (h16)) 0*3))?) `::` (h16) `:` (ls32)) | ((((h16) ((`:` (h16)) 0*4))?) `::` (ls32)) | ((((h16) ((`:` (h16)) 0*5))?) `::` (h16)) | ((((h16) ((`:` (h16)) 0*6))?) `::`))
|
344
344
|
end
|
345
345
|
rule h16
|
346
346
|
((hexdig) 1*4)
|
@@ -352,7 +352,7 @@ rule ipv4address
|
|
352
352
|
((dec_octet) /\u{2e}/i (dec_octet) /\u{2e}/i (dec_octet) /\u{2e}/i (dec_octet))
|
353
353
|
end
|
354
354
|
rule dec_octet
|
355
|
-
((
|
355
|
+
((/25(?:[0-5])/i) | (/2(?:[0-4])/i (digit)) | (`1` ((digit) 2*2)) | (/[1-9]/i (digit)) | (digit))
|
356
356
|
end
|
357
357
|
rule reg_name
|
358
358
|
(((unreserved) | (pct_encoded) | (sub_delims))*)
|
data/lib/dhall/parser.rb
CHANGED
@@ -276,14 +276,15 @@ module Dhall
|
|
276
276
|
module SingleQuoteLiteral
|
277
277
|
def value
|
278
278
|
chunks = capture(:single_quote_continue).value
|
279
|
-
|
280
|
-
|
281
|
-
|
279
|
+
raw = chunks.join
|
280
|
+
indent = raw.scan(/^[ \t]*(?=[^ \t\r\n])/).map(&:chars)
|
281
|
+
.reduce(&Util.method(:longest_common_prefix)).length
|
282
|
+
indent = 0 if raw.end_with?("\n")
|
282
283
|
|
283
284
|
TextLiteral.for(
|
284
285
|
*chunks
|
285
|
-
|
286
|
-
|
286
|
+
.chunk { |c| c != "\n" }
|
287
|
+
.flat_map { |(line, chunk)| line ? chunk[indent..-1] : chunk }
|
287
288
|
)
|
288
289
|
end
|
289
290
|
end
|
@@ -558,9 +559,9 @@ module Dhall
|
|
558
559
|
def value
|
559
560
|
Dhall::Import::EnvironmentVariable.new(
|
560
561
|
if captures.key?(:bash_environment_variable)
|
561
|
-
capture(:bash_environment_variable).
|
562
|
+
capture(:bash_environment_variable).value
|
562
563
|
else
|
563
|
-
capture(:posix_environment_variable).value
|
564
|
+
capture(:posix_environment_variable).value
|
564
565
|
end
|
565
566
|
)
|
566
567
|
end
|
@@ -568,12 +569,22 @@ module Dhall
|
|
568
569
|
|
569
570
|
module PosixEnvironmentVariable
|
570
571
|
def value
|
571
|
-
matches.map(&:value).join
|
572
|
+
matches.map(&:value).join.encode(Encoding::UTF_8)
|
572
573
|
end
|
573
574
|
end
|
574
575
|
|
575
576
|
module PosixEnvironmentVariableCharacter
|
576
|
-
ESCAPES =
|
577
|
+
ESCAPES = {
|
578
|
+
"\"" => "\"",
|
579
|
+
"\\" => "\\",
|
580
|
+
"a" => "\a",
|
581
|
+
"b" => "\b",
|
582
|
+
"f" => "\f",
|
583
|
+
"n" => "\n",
|
584
|
+
"r" => "\r",
|
585
|
+
"t" => "\t",
|
586
|
+
"v" => "\v"
|
587
|
+
}.freeze
|
577
588
|
|
578
589
|
def value
|
579
590
|
if first&.string == "\\"
|
data/lib/dhall/typecheck.rb
CHANGED
@@ -388,11 +388,11 @@ module Dhall
|
|
388
388
|
end
|
389
389
|
|
390
390
|
def element_type
|
391
|
-
@alist.first.value&.type || @alist.element_type
|
391
|
+
(@alist.first.value&.type || @alist.element_type).normalize
|
392
392
|
end
|
393
393
|
|
394
394
|
def element_types
|
395
|
-
@alist.to_a.map(&:type)
|
395
|
+
@alist.to_a.map(&:type).map(&:normalize)
|
396
396
|
end
|
397
397
|
end
|
398
398
|
|
@@ -604,6 +604,25 @@ module Dhall
|
|
604
604
|
end
|
605
605
|
end
|
606
606
|
|
607
|
+
class Enum
|
608
|
+
TypeChecker.register self, Dhall::Enum
|
609
|
+
|
610
|
+
def initialize(enum)
|
611
|
+
@enum = enum
|
612
|
+
end
|
613
|
+
|
614
|
+
def annotate(context)
|
615
|
+
type = Dhall::UnionType.new(
|
616
|
+
alternatives: { @enum.tag => nil }
|
617
|
+
).merge(@enum.alternatives)
|
618
|
+
|
619
|
+
# Annotate to sanity check
|
620
|
+
TypeChecker.for(type).annotate(context)
|
621
|
+
|
622
|
+
Dhall::TypeAnnotation.new(value: @enum, type: type)
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
607
626
|
class Union
|
608
627
|
TypeChecker.register self, Dhall::Union
|
609
628
|
|
@@ -1189,6 +1208,15 @@ module Dhall
|
|
1189
1208
|
class Builtin
|
1190
1209
|
TypeChecker.register self, Dhall::Builtin
|
1191
1210
|
|
1211
|
+
def self.for(builtin)
|
1212
|
+
unfilled = builtin.unfill
|
1213
|
+
if unfilled != builtin
|
1214
|
+
TypeChecker.for(unfilled)
|
1215
|
+
else
|
1216
|
+
new(builtin)
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
|
1192
1220
|
def initialize(builtin)
|
1193
1221
|
@expr = builtin
|
1194
1222
|
@name = builtin.as_json
|
data/lib/dhall/util.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dhall
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Paul Weber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cbor
|
@@ -114,6 +114,7 @@ description: 'This is a Ruby implementation of the Dhall configuration language.
|
|
114
114
|
email:
|
115
115
|
- dev@singpolyma.net
|
116
116
|
executables:
|
117
|
+
- dhall-compile
|
117
118
|
- json-to-dhall
|
118
119
|
- yaml-to-dhall
|
119
120
|
extensions: []
|
@@ -121,6 +122,7 @@ extra_rdoc_files: []
|
|
121
122
|
files:
|
122
123
|
- COPYING
|
123
124
|
- README.md
|
125
|
+
- bin/dhall-compile
|
124
126
|
- bin/json-to-dhall
|
125
127
|
- bin/yaml-to-dhall
|
126
128
|
- dhall.gemspec
|