main.bend

emerging-ezjson@1.3.0.0 · 129 lines · 26 definitions

1# ezjson: JSON for Bend 2, with a parser, a printer and a pull cursor
2#
3# `parse` reads text into Maybe Json. `print` writes compact text and
4# `pretty` indented text. `cursor` reads one event at a time. Build null,
5# booleans, numbers, strings, arrays, and objects; read them with get, at, and
6# as_bool, as_str, as_num, as_u32, as_f32; has and len tell a missing key or
7# index from a null; items lists an array's elements, and is_arr and is_obj
8# tell the containers apart.
9import Base
10import emerging-ezjson@1.3.0.0/src/value.bend as Value
11import emerging-ezjson@1.3.0.0/src/parse.bend as Parse
12import emerging-ezjson@1.3.0.0/src/print.bend as Print
13import emerging-ezjson@1.3.0.0/src/pull.bend as Pull
14import emerging-ezjson@1.3.0.0/src/fixed.bend as Fixed
15
16# a text as a value, or None when it is not JSON
17def parse(txt: String) -> Maybe<&2, Value.Json>:
18  Parse.parse(txt)
19
20# a value as compact JSON
21def print(val: Value.Json) -> String:
22  Print.print(val)
23
24# a value as JSON indented two spaces a level, one element or member a line,
25# with no newline at the end
26def pretty(val: Value.Json) -> String:
27  Print.pretty(val)
28
29# null
30def null() -> Value.Json:
31  Value.null()
32
33# a boolean
34def bool(flag: Bool) -> Value.Json:
35  Value.bool(flag)
36
37# a string
38def str(txt: String) -> Value.Json:
39  Value.str(txt)
40
41# a JSON number from its text, or null when that text is not one
42def num(raw: String) -> Value.Json:
43  Value.num(raw)
44
45# an object from pairs
46def obj(pairs: List<&1, String & Value.Json>) -> Value.Json:
47  Value.obj(pairs)
48
49# an array from a list
50def arr(items: List<&2, Value.Json>) -> Value.Json:
51  Value.arr(items)
52
53# an object's value at a key; JNull when it is not an object or has no such
54# key
55def get(val: Value.Json, key: String) -> Value.Json:
56  Value.get(val, key)
57
58# an array's item at an index; JNull when it is not an array or has none
59def at(val: Value.Json, idx: U32) -> Value.Json:
60  Value.at(val, idx)
61
62# whether an object has a key; false when the value is not an object. Tells
63# a missing key from a key whose value is null, which `get` does not
64def has(val: Value.Json, key: String) -> Bool:
65  Value.has(val, key)
66
67# how many elements an array, or members an object, has; 0 for anything else
68def len(val: Value.Json) -> U32:
69  Value.len(val)
70
71# an array's elements, in order; [] when the value is not an array. One
72# walk of the array, where a loop over `at` walks it again for every index
73def items(val: Value.Json) -> List<&2, Value.Json>:
74  Value.items(val)
75
76# whether a value is an array
77def is_arr(val: Value.Json) -> Bool:
78  Value.is_arr(val)
79
80# whether a value is an object
81def is_obj(val: Value.Json) -> Bool:
82  Value.is_obj(val)
83
84# a boolean, or none when the value is not one
85def as_bool(val: Value.Json) -> Maybe<&2, Bool>:
86  Value.as_bool(val)
87
88# a string, or none when the value is not one
89def as_str(val: Value.Json) -> Maybe<&2, String>:
90  Value.as_str(val)
91
92# a number's text, or none when the value is not a number
93def as_num(val: Value.Json) -> Maybe<&2, String>:
94  Value.as_num(val)
95
96# a number's text written with `places` decimals, rounded half to even on
97# its decimal digits (not through a binary float), as Python's `'%.Nf'`
98# writes a value whose decimal text is exact; None when the text is not a
99# JSON number. A `-` is kept even when the result is zero: `-0.04` to one
100# place is `-0.0`
101def num.fixed(raw: String, places: Nat) -> Maybe<&2, String>:
102  Fixed.fixed(raw, places)
103
104# a number as a U32, or none when it is not one or does not fit
105def as_u32(val: Value.Json) -> Maybe<&2, U32>:
106  Value.as_u32(val)
107
108# a number as an F32, or none when it is not one or does not fit
109def as_f32(val: Value.Json) -> Maybe<&2, F32>:
110  Value.as_f32(val)
111
112# a cursor at the start of a JSON text. It holds the unread suffix of that
113# text. A span event keeps its own suffix, so it stays valid after `next`
114# moves the cursor, and it is gone when the event is dropped
115def cursor(src: String) -> Pull.Cur:
116  Pull.cursor(src)
117
118# the next event. Commas and colons are not events. After the root value,
119# the next call is the end, or an error if another value follows
120def next(cur: Pull.Cur) -> (Pull.Ev & Pull.Cur):
121  Pull.next(cur)
122
123# drop the next value, scalar or container, without building it
124def skip(cur: Pull.Cur) -> Pull.Cur:
125  Pull.skip(cur)
126
127# the text of a string, key, or number event, copying a span. None otherwise
128def text(ev: Pull.Ev) -> Maybe<&2, String>:
129  Pull.text(ev)