ref: cb8b7343a04a8fd959e582b96969f43f2ea0c563
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Oct 5 16:41:06 EDT 2016
First commit.
--- /dev/null
+++ b/lib/json/bld.proj
@@ -1,0 +1,5 @@
+lib json =
+ types.myr
+ parse.myr
+;;
+
--- /dev/null
+++ b/lib/json/parse.myr
@@ -1,0 +1,273 @@
+use std
+
+use "types"
+
+pkg json =
+ const parse : (str : byte[:] -> std.result(elt#, err))
+ const free : (j : elt# -> void)
+;;
+
+type parser = struct
+ str : byte[:]
+ line : std.size
+ off : std.size
+ idx : std.size
+;;
+
+const parse = {str
+ var parser : parser
+
+ parser = [
+ .str = str,
+ .line = 1,
+ .off = 1,
+ .idx = 0,
+ ]
+ -> parseelt(&parser)
+}
+
+const free = {j
+ match j
+ | &(`Null): /* nothing */
+ | &(`Bool _): /* nothing */
+ | &(`Num _): /* nothing */
+ | &(`Str s): std.slfree(s)
+ | &(`Arr a):
+ for e in a
+ free(j)
+ ;;
+ | &(`Obj o):
+ for (k, v) in o
+ std.slfree(k)
+ free(v)
+ ;;
+ ;;
+}
+
+const parseelt = {p
+ takespace(p)
+ match peekc(p)
+ | '{': -> parseobj(p)
+ | '[': -> parsearr(p)
+ | '"': -> parsestr(p)
+ | chr:
+ if std.hasprefix(p.str[p.idx:], "false")
+ -> `std.Ok std.mk(`Bool false)
+ elif std.hasprefix(p.str[p.idx:], "true")
+ -> `std.Ok std.mk(`Bool true)
+ elif std.hasprefix(p.str[p.idx:], "null")
+ -> `std.Ok std.mk(`Null)
+ elif std.isdigit(peekc(p)) || peekc(p) == '-'
+ match parsenum(p)
+ | `std.Some n: -> `std.Ok std.mk(`Num (n : flt64))
+ | `std.None: -> `std.Err `Junk chr
+ ;;
+ else
+ -> `std.Err `Junk chr
+ ;;
+ ;;
+}
+
+const parseobj = {p
+ var membs
+ var err
+
+ std.assert(takec(p) == '{', "should only enter 'obj' after '{'")
+ membs = [][:]
+ while true
+ match member(p)
+ | `std.Ok m:
+ std.slpush(&membs, m)
+ takespace(p)
+ match peekc(p)
+ | ',': /* nothing */
+ | '}': break
+ | chr:
+ err = `Junk chr
+ goto error
+ ;;
+ | `std.Err e:
+ err = e
+ goto error
+ ;;
+ ;;
+ -> `std.Ok std.mk(`Obj membs)
+:error
+ for (k, v) in membs
+ std.slfree(k)
+ free(v)
+ ;;
+ std.slfree(membs)
+ -> `std.Err err
+}
+
+const member = {p
+ var str
+
+ takespace(p)
+ match jsonstr(p)
+ | `std.Ok s: str = s
+ | `std.Err e: -> `std.Err e
+ ;;
+
+ takespace(p)
+ match takec(p)
+ | ':': /* nothing */
+ | chr: -> `std.Err `Junk chr
+ ;;
+
+ takespace(p)
+ match parseelt(p)
+ | `std.Ok elt:
+ -> `std.Ok (str, elt)
+ | `std.Err e:
+ std.slfree(str)
+ -> `std.Err e
+ ;;
+}
+
+const parsearr = {p
+ var elts
+ var err
+
+ std.assert(takec(p) == '[', "should only enter 'obj' after '['")
+ elts = [][:]
+ while true
+ match parseelt(p)
+ | `std.Ok e: std.slpush(&elts, e)
+ | `std.Err e:
+ err = e
+ goto error
+ ;;
+ match peekc(p)
+ | ',': /* nothing */
+ | ']': break
+ | chr:
+ err = `Junk chr
+ goto error
+ ;;
+ ;;
+ -> `std.Ok std.mk(`Arr elts)
+:error
+ for e in elts
+ free(e)
+ ;;
+ std.slfree(elts)
+ -> `std.Err err
+}
+
+const parsestr = {p
+ match jsonstr(p)
+ | `std.Ok str: -> `std.Ok std.mk(`Str str)
+ | `std.Err e: -> `std.Err e
+ ;;
+}
+
+const parsenum = {p -> std.option(int64)
+ var start
+
+ start = p.idx
+ if peekc(p) == '+' || peekc(p) == '-'
+ p.idx++
+ ;;
+ while p.idx < p.str.len
+ if !std.isdigit((p.str[p.idx] : char))
+ break
+ ;;
+ p.idx++
+ ;;
+
+ if peekc(p) == '.'
+ p.idx++
+ while p.idx < p.str.len
+ if !std.isdigit((p.str[p.idx] : char))
+ break
+ ;;
+ p.idx++
+ ;;
+ ;;
+ if peekc(p) == 'e' || peekc(p) == 'E'
+ if peekc(p) == '+' || peekc(p) == '-'
+ p.idx++
+ ;;
+ while p.idx < p.str.len
+ if !std.isdigit((p.str[p.idx] : char))
+ break
+ ;;
+ p.idx++
+ ;;
+ ;;
+
+ -> std.intparse(p.str[start:p.idx])
+}
+
+const jsonstr = {p
+ var sb, idx, err
+
+ sb = std.mksb()
+ match takec(p)
+ | '"': /* nothing */
+ | chr:
+ err = `Junk chr
+ goto error
+ ;;
+ while p.idx < p.str.len
+ match takec(p)
+ | '\\':
+ takec(p)
+ match takec(p)
+ | '"': std.sbputc(sb, '"')
+ | '\\': std.sbputc(sb, '\\')
+ | '/': std.sbputc(sb, '/')
+ | 'b': std.sbputc(sb, '\b')
+ | 'n': std.sbputc(sb, '\n')
+ | 'f': std.sbputc(sb, '\u{0c}')
+ | 'r': std.sbputc(sb, '\r')
+ | 't': std.sbputc(sb, '\t')
+ | chr:
+ err = `Badesc chr
+ goto error
+ ;;
+ | '"':
+ -> `std.Ok std.sbfin(sb)
+ | chr:
+ std.sbputc(sb, chr)
+ idx += std.charlen(chr)
+ ;;
+ ;;
+
+:error
+ std.sbfree(sb)
+ -> `std.Err err
+}
+
+const takespace = {p
+ while true
+ match (p.str[p.idx] : char)
+ | ' ':
+ | '\t':
+ | '\n':
+ | '\r':
+ | _:
+ break
+ ;;
+ p.idx++
+ ;;
+}
+
+const peekc = {p
+ -> std.decode(p.str[p.idx:])
+}
+
+const takec = {p
+ var c
+
+ c = std.decode(p.str[p.idx:])
+ p.idx += std.charlen(c)
+ if c == '\n'
+ p.line++
+ p.off = 1
+ ;;
+ -> c
+}
+
--- /dev/null
+++ b/lib/json/types.myr
@@ -1,0 +1,19 @@
+use std
+
+pkg json =
+ type elt = union
+ `Null
+ `Bool bool
+ `Num flt64
+ `Str byte[:]
+ `Arr elt#[:]
+ `Obj (byte[:], elt#)[:]
+ ;;
+
+ type err = union
+ `Junk char
+ `Badesc char
+ `End
+ ;;
+;;
+