dhall 0.3.0 → 0.4.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.
@@ -2,9 +2,11 @@
2
2
 
3
3
  require "cbor"
4
4
  require "digest/sha2"
5
+ require "multihashes"
5
6
 
6
7
  require "dhall/ast"
7
8
  require "dhall/builtins"
9
+ require "dhall/parser"
8
10
 
9
11
  module Dhall
10
12
  def self.from_binary(cbor_binary)
@@ -34,10 +36,13 @@ module Dhall
34
36
  CBOR.encode(as_json)
35
37
  end
36
38
  end
37
- alias to_binary to_cbor
39
+
40
+ def to_binary
41
+ CBOR.encode(::CBOR::Tagged.new(55799, self))
42
+ end
38
43
 
39
44
  def digest(digest: Digest::SHA2.new(256))
40
- (digest << normalize.to_binary).freeze
45
+ (digest << normalize.to_cbor).freeze
41
46
  end
42
47
 
43
48
  def cache_key
@@ -80,15 +85,21 @@ module Dhall
80
85
 
81
86
  class List
82
87
  def self.decode(type, *els)
83
- type = type.nil? ? nil : Dhall.decode(type)
88
+ type = type.nil? ? nil : Builtins[:List].call(Dhall.decode(type))
84
89
  if els.empty?
85
- EmptyList.new(element_type: type)
90
+ EmptyList.new(type: type)
86
91
  else
87
- List.new(elements: els.map(&Dhall.method(:decode)), element_type: type)
92
+ List.new(elements: els.map(&Dhall.method(:decode)), type: type)
88
93
  end
89
94
  end
90
95
  end
91
96
 
97
+ class EmptyList
98
+ def self.decode(type)
99
+ EmptyList.new(type: Dhall.decode(type))
100
+ end
101
+ end
102
+
92
103
  class Optional
93
104
  def self.decode(type, value=nil)
94
105
  if value.nil?
@@ -102,6 +113,15 @@ module Dhall
102
113
  end
103
114
  end
104
115
 
116
+ class ToMap
117
+ def self.decode(record, type=nil)
118
+ new(
119
+ record: Dhall.decode(record),
120
+ type: type.nil? ? nil : Dhall.decode(type)
121
+ )
122
+ end
123
+ end
124
+
105
125
  class Merge
106
126
  def self.decode(record, input, type=nil)
107
127
  new(
@@ -140,10 +160,14 @@ module Dhall
140
160
 
141
161
  class RecordProjection
142
162
  def self.decode(record, *selectors)
143
- if selectors.empty?
144
- EmptyRecordProjection.new(record: Dhall.decode(record))
163
+ record = Dhall.decode(record)
164
+ if selectors.length == 1 && selectors[0].is_a?(Array)
165
+ RecordProjectionByExpression.new(
166
+ record: record,
167
+ selector: Dhall.decode(selectors[0][0])
168
+ )
145
169
  else
146
- new(record: Dhall.decode(record), selectors: selectors)
170
+ self.for(record, selectors)
147
171
  end
148
172
  end
149
173
  end
@@ -190,13 +214,56 @@ module Dhall
190
214
  end
191
215
 
192
216
  class Import
217
+ class IntegrityCheck
218
+ def self.decode(integrity_check)
219
+ return unless integrity_check
220
+
221
+ IntegrityCheck.new(
222
+ Multihashes.decode(integrity_check).select { |k, _|
223
+ [:code, :digest].include?(k)
224
+ }
225
+ )
226
+ end
227
+ end
228
+
229
+ class URI
230
+ def self.decode(headers, authority, *path, query)
231
+ uri = ::URI.scheme_list[name.split(/::/).last.upcase].build(
232
+ Parser.parse(authority, root: :authority).value.merge(
233
+ path: Util.path_components_to_uri(*path).path
234
+ )
235
+ )
236
+ uri.instance_variable_set(:@query, query)
237
+ new(headers: headers, uri: uri)
238
+ end
239
+ end
240
+
241
+ class Path
242
+ def self.decode(*args)
243
+ new(*args)
244
+ end
245
+ end
246
+
247
+ class EnvironmentVariable
248
+ def self.decode(*args)
249
+ new(*args)
250
+ end
251
+ end
252
+
253
+ class MissingImport
254
+ def self.decode(*args)
255
+ new(*args)
256
+ end
257
+ end
258
+
193
259
  def self.decode(integrity_check, import_type, path_type, *parts)
194
260
  parts[0] = Dhall.decode(parts[0]) if path_type < 2 && !parts[0].nil?
261
+ path_type = PATH_TYPES.fetch(path_type)
195
262
 
196
263
  new(
197
- IntegrityCheck.new(*integrity_check),
264
+ IntegrityCheck.decode(integrity_check),
198
265
  IMPORT_TYPES[import_type],
199
- PATH_TYPES[path_type].new(*parts)
266
+ path_type.decode(*parts)
200
267
  )
201
268
  end
202
269
  end
@@ -275,6 +342,8 @@ module Dhall
275
342
  nil,
276
343
  Import,
277
344
  LetBlock,
278
- TypeAnnotation
345
+ TypeAnnotation,
346
+ ToMap,
347
+ EmptyList
279
348
  ].freeze
280
349
  end
@@ -6,93 +6,74 @@ module Dhall
6
6
  class Builtin < Expression
7
7
  include(ValueSemantics.for_attributes {})
8
8
 
9
- def call(*args)
10
- # Do not auto-normalize builtins to avoid recursion loop
11
- args.reduce(self) do |f, arg|
9
+ def as_json
10
+ self.class.name&.split(/::/)&.last&.tr("_", "/").to_s
11
+ end
12
+ end
13
+
14
+ class BuiltinFunction < Builtin
15
+ include(ValueSemantics.for_attributes do
16
+ partial_application ArrayOf(Expression), default: []
17
+ end)
18
+
19
+ def unfill(*args)
20
+ (args.empty? ? partial_application : args).reduce(self.class.new) do |f, arg|
12
21
  Application.new(function: f, argument: arg)
13
22
  end
14
23
  end
15
24
 
16
- def unfill
17
- attributes.reduce(self.class.new) do |f, attr|
18
- if send(attr.name).nil?
19
- f
20
- else
21
- Application.new(function: f, argument: send(attr.name))
22
- end
25
+ def call(*new_args)
26
+ args = partial_application + new_args
27
+ if args.length == method(:uncurried_call).arity
28
+ uncurried_call(*args)
29
+ else
30
+ with(partial_application: args)
23
31
  end
24
32
  end
25
33
 
26
34
  def as_json
27
- if (unfilled = unfill).class != self.class
35
+ if (unfilled = unfill) != self
28
36
  unfilled.as_json
29
37
  else
30
- self.class.name&.split(/::/)&.last&.tr("_", "/").to_s
38
+ super
31
39
  end
32
40
  end
41
+ end
33
42
 
34
- protected
43
+ module Builtins
44
+ # rubocop:disable Style/ClassAndModuleCamelCase
35
45
 
36
- def attributes
37
- self.class.value_semantics.attributes
38
- end
46
+ class Double_show < BuiltinFunction
47
+ protected
39
48
 
40
- def fill_next_if_valid(value)
41
- with(attributes.each_with_object({}) do |attr, h|
42
- if !send(attr.name).nil?
43
- h[attr.name] = send(attr.name)
44
- elsif attr.validate?(value)
45
- h[attr.name] = value
46
- value = nil
47
- else
48
- return nil
49
- end
50
- end)
51
- end
49
+ def uncurried_call(arg)
50
+ return unfill(arg) unless arg.is_a?(Dhall::Double)
52
51
 
53
- def full?
54
- attributes.all? { |attr| !send(attr.name).nil? }
52
+ Dhall::Text.new(value: arg.to_s)
53
+ end
55
54
  end
56
55
 
57
- def fill_or_call(arg, &block)
58
- full? ? block[arg] : fill_next_if_valid(arg)
59
- end
60
- end
56
+ class Integer_show < BuiltinFunction
57
+ protected
61
58
 
62
- module Builtins
63
- # rubocop:disable Style/ClassAndModuleCamelCase
59
+ def uncurried_call(arg)
60
+ return unfill(arg) unless arg.is_a?(Dhall::Integer)
64
61
 
65
- class Double_show < Builtin
66
- def call(arg)
67
- if arg.is_a?(Dhall::Double)
68
- Dhall::Text.new(value: arg.to_s)
69
- else
70
- super
71
- end
62
+ Dhall::Text.new(value: arg.to_s)
72
63
  end
73
64
  end
74
65
 
75
- class Integer_show < Builtin
76
- def call(arg)
77
- if arg.is_a?(Dhall::Integer)
78
- Dhall::Text.new(value: arg.to_s)
79
- else
80
- super
81
- end
82
- end
83
- end
66
+ class Integer_toDouble < BuiltinFunction
67
+ protected
84
68
 
85
- class Integer_toDouble < Builtin
86
- def call(arg)
87
- if arg.is_a?(Dhall::Integer)
88
- Dhall::Double.new(value: arg.value.to_f)
89
- else
90
- super
91
- end
69
+ def uncurried_call(arg)
70
+ return unfill(arg) unless arg.is_a?(Dhall::Integer)
71
+
72
+ Dhall::Double.new(value: arg.value.to_f)
92
73
  end
93
74
  end
94
75
 
95
- class Natural_build < Builtin
76
+ class Natural_build < BuiltinFunction
96
77
  def fusion(arg, *bogus)
97
78
  if bogus.empty? &&
98
79
  arg.is_a?(Application) &&
@@ -103,7 +84,9 @@ module Dhall
103
84
  end
104
85
  end
105
86
 
106
- def call(arg)
87
+ protected
88
+
89
+ def uncurried_call(arg)
107
90
  arg.call(
108
91
  Natural.new,
109
92
  Function.of_arguments(
@@ -115,79 +98,71 @@ module Dhall
115
98
  end
116
99
  end
117
100
 
118
- class Natural_even < Builtin
119
- def call(nat)
120
- if nat.is_a?(Dhall::Natural)
121
- Dhall::Bool.new(value: nat.even?)
122
- else
123
- super
124
- end
125
- end
126
- end
101
+ class Natural_even < BuiltinFunction
102
+ protected
127
103
 
128
- class Natural_fold < Builtin
129
- include(ValueSemantics.for_attributes do
130
- nat Either(nil, Dhall::Natural), default: nil
131
- type Either(nil, Expression), default: nil
132
- f Either(nil, Expression), default: nil
133
- end)
104
+ def uncurried_call(nat)
105
+ return unfill(nat) unless nat.is_a?(Dhall::Natural)
134
106
 
135
- def call(arg)
136
- fill_or_call(arg) do
137
- if @nat.zero?
138
- arg.normalize
139
- else
140
- @f.call(with(nat: nat.pred).call(arg))
141
- end
142
- end || super
107
+ Dhall::Bool.new(value: nat.even?)
143
108
  end
144
109
  end
145
110
 
146
- class Natural_isZero < Builtin
147
- def call(nat)
148
- if nat.is_a?(Dhall::Natural)
149
- Dhall::Bool.new(value: nat.zero?)
111
+ class Natural_fold < BuiltinFunction
112
+ protected
113
+
114
+ def uncurried_call(nat, type, f, z)
115
+ return unfill(nat, type, f, z) unless nat.is_a?(Dhall::Natural)
116
+
117
+ if nat.zero?
118
+ z.normalize
150
119
  else
151
- super
120
+ f.call(Natural_fold.new.call(nat.pred, type, f, z))
152
121
  end
153
122
  end
154
123
  end
155
124
 
156
- class Natural_odd < Builtin
157
- def call(nat)
158
- if nat.is_a?(Dhall::Natural)
159
- Dhall::Bool.new(value: nat.odd?)
160
- else
161
- super
162
- end
125
+ class Natural_isZero < BuiltinFunction
126
+ protected
127
+
128
+ def uncurried_call(nat)
129
+ return unfill(nat) unless nat.is_a?(Dhall::Natural)
130
+
131
+ Dhall::Bool.new(value: nat.zero?)
163
132
  end
164
133
  end
165
134
 
166
- class Natural_show < Builtin
167
- def call(nat)
168
- if nat.is_a?(Dhall::Natural)
169
- Dhall::Text.new(value: nat.to_s)
170
- else
171
- super
172
- end
135
+ class Natural_odd < BuiltinFunction
136
+ protected
137
+
138
+ def uncurried_call(nat)
139
+ return unfill(nat) unless nat.is_a?(Dhall::Natural)
140
+
141
+ Dhall::Bool.new(value: nat.odd?)
173
142
  end
174
143
  end
175
144
 
176
- class Natural_toInteger < Builtin
177
- def call(nat)
178
- if nat.is_a?(Dhall::Natural)
179
- Dhall::Integer.new(value: nat.value)
180
- else
181
- super
182
- end
145
+ class Natural_show < BuiltinFunction
146
+ protected
147
+
148
+ def uncurried_call(nat)
149
+ return unfill(nat) unless nat.is_a?(Dhall::Natural)
150
+
151
+ Dhall::Text.new(value: nat.to_s)
183
152
  end
184
153
  end
185
154
 
186
- class List_build < Builtin
187
- include(ValueSemantics.for_attributes do
188
- type Either(nil, Expression), default: nil
189
- end)
155
+ class Natural_toInteger < BuiltinFunction
156
+ protected
157
+
158
+ def uncurried_call(nat)
159
+ return unfill(nat) unless nat.is_a?(Dhall::Natural)
160
+
161
+ Dhall::Integer.new(value: nat.value)
162
+ end
163
+ end
190
164
 
165
+ class List_build < BuiltinFunction
191
166
  def fusion(*args)
192
167
  _, arg, = args
193
168
  if arg.is_a?(Application) &&
@@ -199,19 +174,17 @@ module Dhall
199
174
  end
200
175
  end
201
176
 
202
- def call(arg)
203
- fill_or_call(arg) do
204
- arg.call(
205
- List.new.call(type),
206
- cons,
207
- EmptyList.new(element_type: type)
208
- )
209
- end
210
- end
211
-
212
177
  protected
213
178
 
214
- def cons
179
+ def uncurried_call(type, arg)
180
+ arg.call(
181
+ List.new.call(type),
182
+ cons(type),
183
+ EmptyList.new(element_type: type)
184
+ )
185
+ end
186
+
187
+ def cons(type)
215
188
  Function.of_arguments(
216
189
  type,
217
190
  List.new.call(type.shift(1, "_", 0)),
@@ -220,56 +193,33 @@ module Dhall
220
193
  end
221
194
  end
222
195
 
223
- class List_fold < Builtin
224
- include(ValueSemantics.for_attributes do
225
- ltype Either(nil, Expression), default: nil
226
- list Either(nil, List), default: nil
227
- ztype Either(nil, Expression), default: nil
228
- f Either(nil, Expression), default: nil
229
- end)
230
-
231
- def call(arg)
232
- fill_or_call(arg) do
233
- list.reduce(arg, &f).normalize
234
- end || super
235
- end
236
- end
196
+ class List_fold < BuiltinFunction
197
+ protected
237
198
 
238
- class List_head < Builtin
239
- include(ValueSemantics.for_attributes do
240
- type Either(nil, Expression), default: nil
241
- end)
199
+ def uncurried_call(ltype, list, ztype, f, z)
200
+ return unfill(ltype, list, ztype, f, z) unless list.is_a?(Dhall::List)
242
201
 
243
- def call(arg)
244
- fill_or_call(arg) do
245
- if arg.is_a?(Dhall::List)
246
- arg.first
247
- else
248
- super
249
- end
250
- end
202
+ list.reduce(z, &f).normalize
251
203
  end
252
204
  end
253
205
 
254
- class List_indexed < Builtin
255
- include(ValueSemantics.for_attributes do
256
- type Either(nil, Expression), default: nil
257
- end)
206
+ class List_head < BuiltinFunction
207
+ protected
258
208
 
259
- def call(arg)
260
- fill_or_call(arg) do
261
- if arg.is_a?(Dhall::List)
262
- _call(arg)
263
- else
264
- super
265
- end
266
- end
209
+ def uncurried_call(type, list)
210
+ return unfill(type, list) unless list.is_a?(Dhall::List)
211
+
212
+ list.first
267
213
  end
214
+ end
268
215
 
216
+ class List_indexed < BuiltinFunction
269
217
  protected
270
218
 
271
- def _call(arg)
272
- arg.map(type: indexed_type(type)) { |x, idx|
219
+ def uncurried_call(type, list)
220
+ return unfill(type, list) unless list.is_a?(Dhall::List)
221
+
222
+ list.map(type: indexed_type(type)) { |x, idx|
273
223
  Record.new(
274
224
  record: {
275
225
  "index" => Dhall::Natural.new(value: idx),
@@ -289,59 +239,37 @@ module Dhall
289
239
  end
290
240
  end
291
241
 
292
- class List_last < Builtin
293
- include(ValueSemantics.for_attributes do
294
- type Either(nil, Expression), default: nil
295
- end)
242
+ class List_last < BuiltinFunction
243
+ protected
296
244
 
297
- def call(arg)
298
- fill_or_call(arg) do
299
- if arg.is_a?(Dhall::List)
300
- arg.last
301
- else
302
- super
303
- end
304
- end
245
+ def uncurried_call(type, list)
246
+ return unfill(type, list) unless list.is_a?(Dhall::List)
247
+
248
+ list.last
305
249
  end
306
250
  end
307
251
 
308
- class List_length < Builtin
309
- include(ValueSemantics.for_attributes do
310
- type Either(nil, Expression), default: nil
311
- end)
252
+ class List_length < BuiltinFunction
253
+ protected
312
254
 
313
- def call(arg)
314
- fill_or_call(arg) do
315
- if arg.is_a?(Dhall::List)
316
- Dhall::Natural.new(value: arg.length)
317
- else
318
- super
319
- end
320
- end
255
+ def uncurried_call(type, list)
256
+ return unfill(type, list) unless list.is_a?(Dhall::List)
257
+
258
+ Dhall::Natural.new(value: list.length)
321
259
  end
322
260
  end
323
261
 
324
- class List_reverse < Builtin
325
- include(ValueSemantics.for_attributes do
326
- type Either(nil, Expression), default: nil
327
- end)
262
+ class List_reverse < BuiltinFunction
263
+ protected
328
264
 
329
- def call(arg)
330
- fill_or_call(arg) do
331
- if arg.is_a?(Dhall::List)
332
- arg.reverse
333
- else
334
- super
335
- end
336
- end
265
+ def uncurried_call(type, list)
266
+ return unfill(type, list) unless list.is_a?(Dhall::List)
267
+
268
+ list.reverse
337
269
  end
338
270
  end
339
271
 
340
- class Optional_build < Builtin
341
- include(ValueSemantics.for_attributes do
342
- type Either(nil, Expression), default: nil
343
- end)
344
-
272
+ class Optional_build < BuiltinFunction
345
273
  def fusion(*args)
346
274
  _, arg, = args
347
275
  if arg.is_a?(Application) &&
@@ -353,19 +281,17 @@ module Dhall
353
281
  end
354
282
  end
355
283
 
356
- def call(arg)
357
- fill_or_call(arg) do
358
- arg.call(
359
- Optional.new.call(type),
360
- some,
361
- OptionalNone.new(value_type: type)
362
- )
363
- end
364
- end
365
-
366
284
  protected
367
285
 
368
- def some
286
+ def uncurried_call(type, f)
287
+ f.call(
288
+ Optional.new.call(type),
289
+ some(type),
290
+ OptionalNone.new(value_type: type)
291
+ )
292
+ end
293
+
294
+ def some(type)
369
295
  Function.of_arguments(
370
296
  type,
371
297
  body: Dhall::Optional.new(
@@ -376,24 +302,19 @@ module Dhall
376
302
  end
377
303
  end
378
304
 
379
- class Optional_fold < Builtin
380
- include(ValueSemantics.for_attributes do
381
- type Either(nil, Expression), default: nil
382
- optional Either(nil, Optional), default: nil
383
- ztype Either(nil, Expression), default: nil
384
- f Either(nil, Expression), default: nil
385
- end)
305
+ class Optional_fold < BuiltinFunction
306
+ protected
386
307
 
387
- def call(*args)
388
- args.reduce(self) do |fold, arg|
389
- fold.fill_or_call(arg) do
390
- fold.optional.reduce(arg, &fold.f)
391
- end || super
308
+ def uncurried_call(type, optional, ztype, f, z)
309
+ unless optional.is_a?(Dhall::Optional)
310
+ return unfill(type, optional, ztype, f, z)
392
311
  end
312
+
313
+ optional.reduce(z, &f)
393
314
  end
394
315
  end
395
316
 
396
- class Text_show < Builtin
317
+ class Text_show < BuiltinFunction
397
318
  ENCODE = (Hash.new { |_, x| "\\u%04x" % x.ord }).merge(
398
319
  "\"" => "\\\"",
399
320
  "\\" => "\\\\",
@@ -404,17 +325,17 @@ module Dhall
404
325
  "\t" => "\\t"
405
326
  )
406
327
 
407
- def call(arg)
408
- if arg.is_a?(Dhall::Text)
409
- Dhall::Text.new(
410
- value: "\"#{arg.value.gsub(
411
- /["\$\\\b\f\n\r\t\u0000-\u001F]/,
412
- &ENCODE
413
- )}\""
414
- )
415
- else
416
- super
417
- end
328
+ protected
329
+
330
+ def uncurried_call(text)
331
+ return unfill(text) unless text.is_a?(Dhall::Text)
332
+
333
+ Dhall::Text.new(
334
+ value: "\"#{text.to_s.gsub(
335
+ /["\$\\\b\f\n\r\t\u0000-\u001F]/,
336
+ &ENCODE
337
+ )}\""
338
+ )
418
339
  end
419
340
  end
420
341