View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2018, VU University Amsterdam
    7    All rights reserved.
    8
    9    Redistribution and use in source and binary forms, with or without
   10    modification, are permitted provided that the following conditions
   11    are met:
   12
   13    1. Redistributions of source code must retain the above copyright
   14       notice, this list of conditions and the following disclaimer.
   15
   16    2. Redistributions in binary form must reproduce the above copyright
   17       notice, this list of conditions and the following disclaimer in
   18       the documentation and/or other materials provided with the
   19       distribution.
   20
   21    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   22    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   23    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   24    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   25    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   26    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   27    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   28    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   29    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   31    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   32    POSSIBILITY OF SUCH DAMAGE.
   33*/
   34
   35:- module(yaml,
   36          [ yaml_read/2,                        % +Input, -DOM
   37            yaml_write/2,                       % +Output, +DOM
   38            yaml_write/3                        % +Output, +DOM, +Options
   39          ]).   40:- autoload(library(apply),[maplist/3,exclude/3]).   41:- autoload(library(base64),[base64/3]).   42:- use_module(library(debug),[debug/3]).   43:- autoload(library(error),[instantiation_error/1]).   44:- autoload(library(option),[option/2,option/3]).   45:- autoload(library(terms),[term_factorized/3]).   46
   47:- use_foreign_library(foreign(yaml4pl)).

Process YAML data

This module parses YAML serialized data into a Prolog term with structure that is compatible with the JSON library. This library is a wrapper around the C library libyaml. This library forms the basis of the YAML support in several languages and thus guarantees compatibility of our YAML support with other languages. */

   58:- multifile
   59    tagged/3.                         % +Tag, ?String, ?Value
   60
   61:- predicate_options(yaml_write/3, 3,
   62                     [ canonical(boolean),
   63                       unicode(boolean),
   64                       implicit(boolean),
   65                       factorize(boolean)
   66                     ]).
 yaml_read(+Input, -DOM) is det
Parse Input to a YAML DOM. The DOM representation uses the following mapping:
Arguments:
Input- is one of (1) a stream, (2) a term string(Data) or (3) a file name.
bug
- YAML defines that floats do not require a digit after the decimal dot. We use the Prolog parser which does require the decimal dot to be followed by at least one digit. Because the YAML spec intends to match JSON which does require a digit, we ignore this incompatibility, expecting it will be addressed in the next YAML version.
  101yaml_read(In, DOM) :-
  102    setup_call_cleanup(
  103        yaml_open(In, Stream, Close),
  104        yaml_parse_stream(Stream, DOM0),
  105        Close),
  106    finalize_dom(DOM0, DOM).
  107
  108yaml_open(Stream, Stream, Close) :-
  109    is_stream(Stream),
  110    !,
  111    stream_property(Stream, eof_action(EOF0)),
  112    (   EOF0 == eof_code
  113    ->  Close = true
  114    ;   set_stream(Stream, eof_action(eof_code)),
  115        Close = set_stream(Stream, eof_action(EOF0))
  116    ).
  117yaml_open(string(Data), Stream, close(Stream)) :-
  118    open_string(Data, Stream),
  119    set_stream(Stream, eof_action(eof_code)).
  120yaml_open(File, Stream, close(Stream)) :-
  121    open(File, read, Stream,
  122         [ eof_action(eof_code)
  123         ]).
  124
  125finalize_dom(Var, _) :-
  126    var(Var),                                   % node in progress
  127    !.
  128finalize_dom(sequence(Elems0, Done, Elems), Elems) :-
  129    !,
  130    (   var(Done)
  131    ->  Done = true,
  132        maplist(finalize_dom, Elems0, Elems)
  133    ;   true
  134    ).
  135finalize_dom(mapping(Attrs0, Done, Dict), Dict) :-
  136    !,
  137    (   var(Done)
  138    ->  Done = true,
  139        maplist(mapping_pair, Attrs0, Pairs),
  140        dict_pairs(Dict, yaml, Pairs)
  141    ;   true
  142    ).
  143finalize_dom(tag(Tag, ValueIn), Value) :-
  144    !,
  145    (   string(ValueIn)
  146    ->  (   yalm_tagged(Tag, ValueIn, Value0)
  147        ->  Value = Value0
  148        ;   debug(yaml(tag), 'Ignored tag ~p for ~p', [Tag, ValueIn]),
  149            Value = tag(Tag, ValueIn)
  150        )
  151    ;   finalize_dom(ValueIn, ValueOut),
  152        Value = tag(Tag, ValueOut)
  153    ).
  154finalize_dom(Value, Value).
  155
  156mapping_pair(Name=Value0, Name-Value) :-
  157    finalize_dom(Value0, Value).
  158
  159yalm_tagged(Tag, String, Value) :-
  160    tagged(Tag, String, Value), !.
  161yalm_tagged('tag:yaml.org,2002:binary', Base64, Data) :-
  162    string_codes(Base64, EncCodes0),
  163    exclude(whitespace, EncCodes0, EncCodes),
  164    phrase(base64(PlainCodes), EncCodes),
  165    string_codes(Data, PlainCodes).
  166yalm_tagged('tag:yaml.org,2002:str', String, String).
  167yalm_tagged('tag:yaml.org,2002:null', "null", null).
  168yalm_tagged('tag:yaml.org,2002:bool', "true", true).
  169yalm_tagged('tag:yaml.org,2002:bool', "false", false).
  170yalm_tagged('tag:yaml.org,2002:int',  String, Int) :-
  171    number_string(Int, String).
  172yalm_tagged('tag:yaml.org,2002:float', String, Float) :-
  173    (   special_float(String, Float)
  174    ->  true
  175    ;   number_string(Float0, String),
  176        Float is float(Float0)
  177    ).
  178
  179special_float(".nan", NaN) :- NaN is nan.
  180special_float(".NaN", NaN) :- NaN is nan.
  181special_float(".NAN", NaN) :- NaN is nan.
  182special_float(".inf", Inf) :- Inf is inf.
  183special_float(".Inf", Inf) :- Inf is inf.
  184special_float(".INF", Inf) :- Inf is inf.
  185special_float("-.inf", Inf) :- Inf is -inf.
  186special_float("-.Inf", Inf) :- Inf is -inf.
  187special_float("-.INF", Inf) :- Inf is -inf.
  188
  189whitespace(0'\s).
  190whitespace(0'\t).
  191whitespace(0'\r).
  192whitespace(0'\n).
  193
  194		 /*******************************
  195		 *             EMITTER		*
  196		 *******************************/
 yaml_write(+Out:stream, +DOM) is det
 yaml_write(+Out:stream, +DOM, +Options) is det
Emit a YAML DOM object as a serialized YAML document to the stream Out. Options processed are:
canonical(+Boolean)
Use canonical representation. Default is false.
unicode(+Boolean)
Use unicode Default is true.
implicit(+Boolean)
Use implicit or explicit representation. Currently only affects the opening and closing the document. Default is true. Use false for embedded documents.
factorize(+Boolean)
If true, minimize the term by factoring out common structures and use &anchor and *anchor. Factorization is always used if DOM is a cyclic term.
  217yaml_write(To, DOM) :-
  218    yaml_write(To, DOM, []).
  219
  220yaml_write(To, DOM, Options) :-
  221    (   option(factorize(true), Options)
  222    ->  true
  223    ;   cyclic_term(DOM)
  224    ),
  225    !,
  226    term_factorized(DOM, Skeleton, Substitutions),
  227    assign_anchors(Substitutions, 1),
  228    yaml_write2(To, Skeleton, Options).
  229yaml_write(To, DOM, Options) :-
  230    yaml_write2(To, DOM, Options).
  231
  232assign_anchors([], _).
  233assign_anchors([anchored(Anchor,_Done,Term)=Term|T], I) :-
  234    string_concat("a", I, Anchor),
  235    I2 is I + 1,
  236    assign_anchors(T, I2).
  237
  238yaml_write2(To, DOM, Options) :-
  239    option(implicit(Implicit), Options, true),
  240    yaml_emitter_create(Emitter, To, Options),
  241    yaml_emit_event(Emitter, stream_start),
  242    yaml_emit_event(Emitter, document_start(Implicit)),
  243    yaml_emit(DOM, Emitter, Options),
  244    yaml_emit_event(Emitter, document_end(Implicit)),
  245    yaml_emit_event(Emitter, stream_end).
  246
  247yaml_emit(Var, _, _) :-
  248    var(Var),
  249    !,
  250    instantiation_error(Var).
  251yaml_emit(anchored(Anchor, Done, Term), Emitter, Options) :-
  252    !,
  253    (   var(Done)
  254    ->  Done = true,
  255        yaml_emit(Term, Emitter, Anchor, Options)
  256    ;   yaml_emit_event(Emitter, alias(Anchor))
  257    ).
  258yaml_emit(Term, Emitter, Options) :-
  259    yaml_emit(Term, Emitter, _Anchor, Options).
  260
  261yaml_emit(List, Emitter, Anchor, Options) :-
  262    is_list(List),
  263    !,
  264    yaml_emit_event(Emitter, sequence_start(Anchor, _Tag)),
  265    yaml_emit_list_elements(List, Emitter, Options),
  266    yaml_emit_event(Emitter, sequence_end).
  267yaml_emit(Dict, Emitter, Anchor, Options) :-
  268    is_dict(Dict, _),
  269    !,
  270    dict_pairs(Dict, _, Pairs),
  271    emit_mapping(Pairs, Emitter, Anchor, Options).
  272yaml_emit(json(Pairs), Emitter, Anchor, Options) :-
  273    !,
  274    emit_mapping(Pairs, Emitter, Anchor, Options).
  275yaml_emit(yaml(Pairs), Emitter, Anchor, Options) :-
  276    !,
  277    emit_mapping(Pairs, Emitter, Anchor, Options).
  278yaml_emit(Scalar, Emitter, Anchor, _Options) :-
  279    yaml_emit_event(Emitter, scalar(Scalar, _Tag, Anchor, plain)).
  280
  281yaml_emit_list_elements([], _, _).
  282yaml_emit_list_elements([H|T], Emitter, Options) :-
  283    yaml_emit(H, Emitter, Options),
  284    yaml_emit_list_elements(T, Emitter, Options).
  285
  286emit_mapping(Pairs, Emitter, Anchor, Options) :-
  287    yaml_emit_event(Emitter, mapping_start(Anchor, _Tag)),
  288    yaml_emit_mapping_elements(Pairs, Emitter, Options),
  289    yaml_emit_event(Emitter, mapping_end).
  290
  291yaml_emit_mapping_elements([], _, _).
  292yaml_emit_mapping_elements([H|T], Emitter, Options) :-
  293    name_value(H, Name, Value),
  294    yaml_emit(Name, Emitter, Options),
  295    yaml_emit(Value, Emitter, Options),
  296    yaml_emit_mapping_elements(T, Emitter, Options).
  297
  298name_value(Name-Value, Name, Value) :- !.
  299name_value(Name=Value, Name, Value) :- !.
  300name_value(NameValue, Name, Value) :-
  301    NameValue =.. [Name,Value].
  302
  303
  304		 /*******************************
  305		 *            HOOKS		*
  306		 *******************************/
 tagged(+Tag, ?String, ?Value) is semidet
Hook that allows convering !!tag values to be decoded or encoded.