yaml.bend

yaml-for-bend@0.1.0.0 · 99 lines · 0 definitions

1# YAML for Bend: read YAML text into values and write values back as YAML.
2#
3#   import ./yaml.bend as Y
4#   import ./value.bend as V
5#
6#   Y.load("a: [1, 2]")    # Done{V.Mapping{[V.Entry{V.Str{"a"}, V.Seq{...}}]}}
7#
8# load reads under the YAML 1.2 Core schema; load.v11 reads the YAML 1.1
9# types (yes/no booleans, 0 octal, base 60, timestamps, "<<" merges).
10# Errors say what went wrong and where: T.error.show(e) is "mapping values
11# are not allowed in this context at line 1 column 5".
12
13import Base
14
15import yaml-for-bend@0.1.0.0/token.bend as T
16
17import yaml-for-bend@0.1.0.0/parse.bend as P
18
19import yaml-for-bend@0.1.0.0/value.bend as V
20
21import yaml-for-bend@0.1.0.0/compose.bend as C
22
23import yaml-for-bend@0.1.0.0/emit.bend as E
24
25def doc.vals(ds: List<&2, C.Doc>) -> List<&2, V.Yaml>:
26  match ds:
27    case Nil{}:
28      []
29    case Con{d, rest}:
30      match d:
31        case C.Doc{v, at}:
32          v <> doc.vals(rest)
33
34def all.of(r: Result<&2, &2, T.Error, List<&2, C.Doc>>) -> Result<&2, &2, T.Error, List<&2, V.Yaml>>:
35  match r:
36    case Fail{e}:
37      Fail{e}
38    case Done{ds}:
39      Done{doc.vals(ds)}
40
41def one.of(r: Result<&2, &2, T.Error, List<&2, C.Doc>>) -> Result<&2, &2, T.Error, V.Yaml>:
42  match r:
43    case Fail{e}:
44      Fail{e}
45    case Done{ds}:
46      match ds:
47        case Nil{}:
48          Done{V.Null{}}
49        case Con{d, rest}:
50          match d:
51            case C.Doc{v, at}:
52              match rest:
53                case Nil{}:
54                  Done{v}
55                case Con{other, more}:
56                  match other:
57                    case C.Doc{w, second}:
58                      Fail{T.Error{"found a second document where load expects one; use load.all", second, T.Content{}}}
59
60# Every document in +text+ under schema +s+, with aliases making at most
61# +limit+ nodes in a document.
62def load.all.with(s: C.Schema, limit: Nat, text: String) -> Result<&2, &2, T.Error, List<&2, V.Yaml>>:
63  all.of(C.compose.limited(P.events(text), s, limit))
64
65# The one document in +text+ under schema +s+: null when there is none, an
66# error when there are more.
67def load.with(s: C.Schema, limit: Nat, text: String) -> Result<&2, &2, T.Error, V.Yaml>:
68  one.of(C.compose.limited(P.events(text), s, limit))
69
70# The one document in +text+ under the YAML 1.2 Core schema: null when
71# there is none, an error when there are more. A repeated key is an error,
72# and so is a document whose aliases make more than 100000 nodes.
73def load(text: String) -> Result<&2, &2, T.Error, V.Yaml>:
74  load.with(C.Core{}, C.alias.limit(), text)
75
76# Every document in +text+, under the Core schema.
77def load.all(text: String) -> Result<&2, &2, T.Error, List<&2, V.Yaml>>:
78  load.all.with(C.Core{}, C.alias.limit(), text)
79
80# load, reading the YAML 1.1 types.
81def load.v11(text: String) -> Result<&2, &2, T.Error, V.Yaml>:
82  load.with(C.Yaml11{}, C.alias.limit(), text)
83
84# load.all, reading the YAML 1.1 types.
85def load.all.v11(text: String) -> Result<&2, &2, T.Error, List<&2, V.Yaml>>:
86  load.all.with(C.Yaml11{}, C.alias.limit(), text)
87
88# The events of +text+, as the parser emits them, and the error that ended
89# them early, if one did.
90def events(text: String) -> P.Parsed:
91  P.events(text)
92
93# +v+ as YAML text in block style, which load reads back as +v+.
94def dump(v: V.Yaml) -> String:
95  E.dump(v)
96
97# Values as a stream of documents, each after "---".
98def dump.all(vs: List<&2, V.Yaml>) -> String:
99  E.dump.all(vs)