33
33
events :: [yaml_libyaml :event ()],
34
34
anchors :: dict (),
35
35
schema :: atom (),
36
- schema_state :: term (),
37
- sort_mappings :: boolean ()
36
+ schema_state :: term ()
38
37
}).
39
38
% composer state
40
39
@@ -54,8 +53,7 @@ compose(Events, Opts) ->
54
53
events = Events ,
55
54
anchors = dict :new (),
56
55
schema = Schema ,
57
- schema_state = Schema :init (Opts ),
58
- sort_mappings = proplists :get_bool (sort_mappings , Opts )
56
+ schema_state = Schema :init (Opts )
59
57
},
60
58
catch compose_stream (State ).
61
59
@@ -79,15 +77,15 @@ compose_doc(State0 = #state{events=[{document_start, _,_,_}, {document_end, _,_,
79
77
State1 = State0 # state {events = Rest },
80
78
{ok , null , State1 };
81
79
82
- % normal document case
80
+ % normal document case
83
81
compose_doc (State0 = # state {events = [{document_start , _ ,_ ,_ } | Rest ]}) ->
84
82
State1 = State0 # state {events = Rest },
85
83
{{_ResolvedTag , ConstructedValue }, State2 } = compose_node (State1 ),
86
-
84
+
87
85
% remove document_end
88
86
[{document_end , _ ,_ ,_ } | Rest2 ] = State2 # state .events ,
89
87
State3 = State2 # state {events = Rest2 },
90
-
88
+
91
89
{ok , ConstructedValue , State3 };
92
90
93
91
% stream end case
@@ -96,8 +94,8 @@ compose_doc(State0 = #state{events=[{stream_end, _,_,_}]}) ->
96
94
{stream_end , State1 }.
97
95
98
96
99
- -spec compose_node (# state {}) -> {ynode (), # state {}}.
100
- % handle scalar
97
+ -spec compose_node (# state {}) -> {ynode (), # state {}}.
98
+ % handle scalar
101
99
compose_node (State0 = # state {
102
100
events = [Head = {scalar , {Anchor ,Tag ,Value ,Style },_ ,_ } |Rest ],
103
101
schema = Schema ,
@@ -165,7 +163,7 @@ compose_node(State0 = #state{
165
163
166
164
167
165
168
- -spec compose_sequence ([ynode ()], # state {}) -> {sequence (), # state {}}.
166
+ -spec compose_sequence ([ynode ()], # state {}) -> {sequence (), # state {}}.
169
167
compose_sequence (ConstructedValues , State0 = # state {
170
168
events = [{sequence_end , _ ,_ ,_ } |Rest ]}) ->
171
169
State1 = State0 # state {events = Rest },
@@ -176,74 +174,57 @@ compose_sequence(ConstructedValues, State0) ->
176
174
compose_sequence ([ConstructedValue |ConstructedValues ], State1 ).
177
175
178
176
179
- -spec compose_mapping (# state {}) -> {mapping (), # state {}}.
180
- compose_mapping (State ) -> compose_mapping (dict :new (), dict :new (), State ).
181
- compose_mapping (Map0 , Merge , State0 = # state {
182
- events = [{mapping_end , _ ,_ ,_ } |Rest ]}) ->
177
+ -spec compose_mapping (# state {}) -> {mapping (), # state {}}.
178
+ compose_mapping (State ) -> compose_mapping (#{}, #{}, State ).
179
+
180
+ % % Accumulate plain old mapping entries in Map, and merge entries in Merge.
181
+ compose_mapping (Map0 , Merge , State0 = # state {events = [{mapping_end , _ ,_ ,_ } |Rest ]}) ->
183
182
State1 = State0 # state {events = Rest },
184
-
183
+
185
184
% notes from http://yaml.org/type/merge.html
186
185
% - merged keys do not overwrite any other keys
187
186
% - latter merged keys do not overwrite earlier merged keys
188
- Map1 = dict :merge (fun (_K , V1 , _V2 ) -> V1 end , Map0 , Merge ),
189
- List0 = dict :to_list (Map1 ),
190
- List1 = case State0 # state .sort_mappings of
191
- true -> lists :keysort (1 ,List0 );
192
- _ -> List0
193
- end ,
194
- { List1 , State1 };
187
+ { maps :merge (Merge , Map0 ), % keys in Map take precendence over Merge
188
+ State1 };
195
189
196
190
compose_mapping (Map0 , Merge0 , State0 ) ->
197
191
{{ KTag , Key }, State1 } = compose_node (State0 ),
198
192
{{ VTag , Value }, State2 } = compose_node (State1 ),
199
-
193
+
200
194
case {KTag , VTag } of
195
+ % % add single mapping to merge map
201
196
{'tag:yaml.org,2002:merge' , 'tag:yaml.org,2002:map' } ->
202
- Merge1 = case catch merge_list_unique (Value , Merge0 ) of
203
- badarg -> merge_error (hd (State1 # state .events ));
204
- Else -> Else
205
- end ,
197
+ Merge1 = maps :merge (Value , Merge0 ),
206
198
compose_mapping (Map0 , Merge1 , State2 );
199
+
200
+ % % add list of mappings to merge map
207
201
{'tag:yaml.org,2002:merge' , 'tag:yaml.org,2002:seq' } ->
208
- Merge1 = case catch lists :foldl (fun merge_list_unique /2 , Merge0 , Value ) of
209
- badarg -> merge_error (hd (State1 # state .events ));
210
- Else -> Else
202
+ Merge1 = case catch lists :foldl (fun maps :merge /2 , Merge0 , Value ) of
203
+ badmap ->
204
+ throw_error (" Merge sequence must contain only mappings" , hd (State1 # state .events ));
205
+ Else when is_map (Else ) ->
206
+ Else
211
207
end ,
212
208
compose_mapping (Map0 , Merge1 , State2 );
209
+
213
210
{'tag:yaml.org,2002:merge' , _ } ->
214
- merge_error (hd (State1 # state .events ));
211
+ throw_error (" Merge value must be mapping or sequence of mappings" , hd (State1 # state .events ));
212
+
215
213
_ ->
216
- Map1 = case dict :is_key (Key , Map0 ) of
217
- false -> dict : store (Key ,Value ,Map0 );
214
+ Map1 = case maps :is_key (Key , Map0 ) of
215
+ false -> maps : put (Key , Value , Map0 );
218
216
true -> throw_error (" Duplicate key" , hd (State0 # state .events ))
219
217
end ,
220
218
compose_mapping (Map1 , Merge0 , State2 )
221
219
end .
222
220
223
- merge_error (Event ) ->
224
- throw_error (" Merge value must be mapping or sequence of mappings" , Event ).
225
-
226
- % merge list of items into dict only if key is not already present
227
- merge_list_unique (List , Dict ) when is_list (List ) ->
228
- lists :foldl (
229
- fun ({K ,V }, D ) ->
230
- case dict :is_key (K , D ) of
231
- false -> dict :store (K ,V ,D );
232
- true -> D
233
- end ;
234
- (_ ,_D ) ->
235
- throw (badarg )
236
- end ,
237
- Dict , List );
238
- merge_list_unique (_List , _Dict ) -> throw (badarg ).
239
-
240
221
-spec maybe_anchor (Anchor , Value , Event , State ) -> # state {}
241
222
when
242
223
Anchor :: null | binary (),
243
224
Value :: term (),
244
225
Event :: yaml_libyaml :event (),
245
226
State :: # state {}.
246
-
227
+
247
228
maybe_anchor (null , _Value , _Event , State0 ) -> State0 ;
248
229
maybe_anchor (Anchor , Value , Event , State0 = # state {anchors = Anchors0 }) ->
249
230
case dict :is_key (Anchor , Anchors0 ) of
0 commit comments