aboutsummaryrefslogtreecommitdiff
path: root/lib/json
diff options
context:
space:
mode:
Diffstat (limited to 'lib/json')
-rw-r--r--lib/json/CHANGES.md5
-rw-r--r--lib/json/README.md18
-rw-r--r--lib/json/json.tm173
3 files changed, 0 insertions, 196 deletions
diff --git a/lib/json/CHANGES.md b/lib/json/CHANGES.md
deleted file mode 100644
index 42ae752c..00000000
--- a/lib/json/CHANGES.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Version History
-
-## v1.0
-
-Initial version
diff --git a/lib/json/README.md b/lib/json/README.md
deleted file mode 100644
index 33e2101a..00000000
--- a/lib/json/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# JSON
-
-This is a library for encoding/decoding JSON values.
-
-## Usage
-
-```tomo
->> j := JSON({"key1"=123, "key2"=[yes, {"ok"="inner"}, JSON.Null]})
-= JSON.Object({"key1"=Number(123), "key2"=Array([Boolean(yes), Object({"ok"=String("inner")}), Null])})
-
-say("$(j.encode())")
-say("$(j.pretty_print())")
-
-when JSON.parse("[1, null, true]") is Success(obj)
- >> obj
-is Failure(msg)
- fail("Failed to parse JSON: $msg")
-```
diff --git a/lib/json/json.tm b/lib/json/json.tm
deleted file mode 100644
index 8127ce52..00000000
--- a/lib/json/json.tm
+++ /dev/null
@@ -1,173 +0,0 @@
-# Base 64 encoding and decoding
-use patterns
-
-enum JSONDecodeResult(
- Success(json:JSON)
- Failure(reason:Text)
-)
- func invalid(text:Text -> JSONDecodeResult)
- return Failure("Unrecognized JSON: $(text.quoted())")
-
-extend Text
- func json_quoted(text:Text -> Text)
- return '"' ++ text.translate({
- "\\"="\\\\",
- '"'='\\"',
- "\f"="\\f",
- "\r"="\\r",
- "\n"="\\n",
- "\b"="\\b",
- "\t"="\\t",
- }) ++ '"'
-
-enum JSON(
- Object(items:{Text=JSON})
- Array(items:[JSON])
- Boolean(value:Bool)
- String(text:Text)
- Number(n:Num)
- Null
-)
- func encode(j:JSON -> Text)
- when j is Object(items)
- return "{" ++ ", ".join([
- '$(k.json_quoted()): $(v.encode())'
- for k,v in items
- ]) ++ "}"
- is Array(items)
- return "[" ++ ", ".join([item.encode() for item in items]) ++ "]"
- is Boolean(value)
- return (if value then "true" else "false")
- is String(text)
- return text.json_quoted()
- is Number(n)
- return "$n"
- is Null
- return "null"
-
- func pretty_print(j:JSON, max_line:Int=80, indent:Text=" ", current_indent:Text="" -> Text)
- inline := j.encode()
- if inline.length > max_line
- next_indent := current_indent ++ indent
- when j is Object(items)
- return "{\n$next_indent" ++ ",\n$next_indent".join([
- '$(k.json_quoted()): $(v.pretty_print(max_line, indent, next_indent))'
- for k,v in items
- ]) ++ "\n$current_indent}"
- is Array(items)
- return "[\n$next_indent" ++ ",\n$next_indent".join([item.pretty_print(max_line, indent, next_indent) for item in items]) ++ "\n$current_indent]"
- else pass
-
- return inline
-
- func parse_text(text:Text, remainder:&Text? = none -> JSONDecodeResult)
- if text.starts_with('"')
- string := ""
- pos := 2
- escapes := {"n"="\n", "t"="\t", "r"="\r", '"'='"', "\\"="\\", "/"="/", "b"="\b", "f"="\f"}
- while pos <= text.length
- c := text[pos]
- if c == '"'
- if remainder
- remainder[] = text.from(pos + 1)
- return Success(JSON.String(string))
-
- if c == "\\"
- stop if pos + 1 > text.length
-
- if esc := escapes[text[pos+1]]
- string ++= esc
- pos += 2
- else if m := text.matching_pattern($Pat/u{4 digit}/)
- string ++= Text.from_codepoints([Int32.parse(m.captures[1])!])
- pos += 1 + m.text.length
- else
- if remainder
- remainder[] = text
- return JSONDecodeResult.invalid(text)
- else
- string ++= c
- pos += 1
-
- if remainder
- remainder[] = text
- return JSONDecodeResult.invalid(text)
-
- func parse(text:Text, remainder:&Text? = none, trailing_commas:Bool=no -> JSONDecodeResult)
- if text.starts_with("true", remainder)
- return Success(JSON.Boolean(yes))
- else if text.starts_with("false", remainder)
- return Success(JSON.Boolean(no))
- else if text.starts_with("null", remainder)
- return Success(JSON.Null)
- else if n := Num.parse(text, remainder)
- return Success(JSON.Number(n))
- else if text.starts_with('"')
- return JSON.parse_text(text, remainder)
- else if text.starts_with("[")
- elements : &[JSON]
- text = text.from(2).trim_pattern($Pat"{whitespace}", right=no)
- repeat
- when JSON.parse(text, &text) is Success(elem)
- elements.insert(elem)
- else stop
-
- if delim := text.matching_pattern($Pat'{0+ ws},{0+ ws}')
- text = text.from(delim.text.length + 1)
- else stop
-
- if trailing_commas
- if delim := text.matching_pattern($Pat'{0+ ws},{0+ ws}')
- text = text.from(delim.text.length + 1)
-
- if terminator := text.matching_pattern($Pat'{0+ ws}]')
- if remainder
- remainder[] = text.from(terminator.text.length + 1)
- return Success(JSON.Array(elements))
- else if text.starts_with("{")
- object : &{Text=JSON}
- text = text.from(2).trim_pattern($Pat"{whitespace}", right=no)
- repeat
- key_text := text
- when JSON.parse_text(text, &text) is Success(key)
- if separator := text.matching_pattern($Pat'{0+ ws}:{0+ ws}')
- text = text.from(separator.text.length + 1)
- else
- return JSONDecodeResult.invalid(text)
-
- when JSON.parse(text, &text) is Success(value)
- when key is String(str)
- object[str] = value
- else
- return JSONDecodeResult.invalid(key_text)
- else
- return JSONDecodeResult.invalid(text)
- else stop
-
- if delim := text.matching_pattern($Pat'{0+ ws},{0+ ws}')
- text = text.from(delim.text.length + 1)
- else stop
-
- if trailing_commas
- if delim := text.matching_pattern($Pat'{0+ ws},{0+ ws}')
- text = text.from(delim.text.length + 1)
-
- if terminator := text.matching_pattern($Pat'{0+ ws}{}}')
- if remainder
- remainder[] = text.from(terminator.text.length + 1)
- return Success(JSON.Object(object))
-
- return JSONDecodeResult.invalid(text)
-
-func main(input=(/dev/stdin), pretty_print:Bool = no, trailing_commas:Bool = yes)
- text := (input.read() or exit("Invalid file: $input")).trim_pattern($Pat"{whitespace}")
- while text.length > 0
- when JSON.parse(text, remainder=&text, trailing_commas=trailing_commas) is Success(json)
- if pretty_print
- say(json.pretty_print())
- else
- say(json.encode())
- is Failure(msg)
- exit("\033[31;1m$msg\033[m", code=1)
-
- text = text.trim_pattern($Pat"{whitespace}")