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