Packages

A JSON parser that decodes JSON into a flat (non recursive) data structure.

Current section

Files

Jump to
julienne src julienne.gleam
Raw

src/julienne.gleam

import gleam/bit_array
import gleam/bytes_tree
import gleam/list
import gleam/result.{try}
pub fn parse(buffer) -> Result(List(#(Term, Int)), _) {
parse_bits(<<buffer:utf8>>)
}
pub fn parse_bits(buffer) {
value(buffer, [], [])
}
pub type Term {
Boolean(Bool)
Null
String(String)
Integer(integer: Int)
// All e numbers are floats as the exponent may be negative
Number(sign: Sign, integer: Int, decimal: #(Int, Int), exponent: Int)
Array
Object
Field(String)
}
pub type Sign {
Positive
Negative
}
type Stack {
ArrayItem
ObjectField
}
pub type Reason {
UnexpectedEnd
UnexpectedToken(BitArray)
MissingDigits
InvalidString(BitArray)
}
// tokenising is a way to drop whitespace
fn value(buffer, stack, acc) -> Result(List(#(Term, Int)), _) {
let depth = list.length(stack)
case buffer, stack {
<<"\r", rest:bits>>, _
| <<"\n", rest:bits>>, _
| <<" ", rest:bits>>, _
| <<"\t", rest:bits>>, _
-> value(rest, stack, acc)
<<"true", rest:bits>>, _ ->
continue(rest, stack, [#(Boolean(True), depth), ..acc])
<<"false", rest:bits>>, _ ->
continue(rest, stack, [#(Boolean(False), depth), ..acc])
<<"null", rest:bits>>, _ -> continue(rest, stack, [#(Null, depth), ..acc])
<<"[", rest:bits>>, _ ->
value(rest, [ArrayItem, ..stack], [#(Array, depth), ..acc])
<<"{", rest:bits>>, _ -> {
let acc = [#(Object, depth), ..acc]
let stack = [ObjectField, ..stack]
key(rest, stack, acc)
}
<<"]", rest:bits>>, [ArrayItem, ..stack] -> continue(rest, stack, acc)
<<"\"", rest:bits>>, _ -> {
use #(extracted, rest) <- try(string(rest, bytes_tree.new()))
continue(rest, stack, [#(String(extracted), depth), ..acc])
}
<<"0.", rest:bits>>, _ -> start_decimal(Positive, 0, rest, stack, acc)
<<"-0.", rest:bits>>, _ -> start_decimal(Negative, 0, rest, stack, acc)
<<"0e", rest:bits>>, _ | <<"0E", rest:bits>>, _ ->
start_exponent(Positive, 0, #(0, 0), rest, stack, acc)
<<"-0e", rest:bits>>, _ | <<"-0E", rest:bits>>, _ ->
start_exponent(Negative, 0, #(0, 0), rest, stack, acc)
<<"0", rest:bits>>, _ | <<"-0", rest:bits>>, _ ->
continue(rest, stack, [#(Integer(0), depth), ..acc])
<<"1", rest:bits>>, _ -> start_number(Positive, 1, rest, stack, acc)
<<"2", rest:bits>>, _ -> start_number(Positive, 2, rest, stack, acc)
<<"3", rest:bits>>, _ -> start_number(Positive, 3, rest, stack, acc)
<<"4", rest:bits>>, _ -> start_number(Positive, 4, rest, stack, acc)
<<"5", rest:bits>>, _ -> start_number(Positive, 5, rest, stack, acc)
<<"6", rest:bits>>, _ -> start_number(Positive, 6, rest, stack, acc)
<<"7", rest:bits>>, _ -> start_number(Positive, 7, rest, stack, acc)
<<"8", rest:bits>>, _ -> start_number(Positive, 8, rest, stack, acc)
<<"9", rest:bits>>, _ -> start_number(Positive, 9, rest, stack, acc)
<<"-1", rest:bits>>, _ -> start_number(Negative, 1, rest, stack, acc)
<<"-2", rest:bits>>, _ -> start_number(Negative, 2, rest, stack, acc)
<<"-3", rest:bits>>, _ -> start_number(Negative, 3, rest, stack, acc)
<<"-4", rest:bits>>, _ -> start_number(Negative, 4, rest, stack, acc)
<<"-5", rest:bits>>, _ -> start_number(Negative, 5, rest, stack, acc)
<<"-6", rest:bits>>, _ -> start_number(Negative, 6, rest, stack, acc)
<<"-7", rest:bits>>, _ -> start_number(Negative, 7, rest, stack, acc)
<<"-8", rest:bits>>, _ -> start_number(Negative, 8, rest, stack, acc)
<<"-9", rest:bits>>, _ -> start_number(Negative, 9, rest, stack, acc)
<<>>, _ -> Error(UnexpectedEnd)
_, _ -> Error(UnexpectedToken(buffer))
}
}
fn key(buffer, stack, acc) {
let depth = list.length(stack)
case buffer {
<<"\r", rest:bits>>
| <<"\n", rest:bits>>
| <<" ", rest:bits>>
| <<"\t", rest:bits>> -> key(rest, stack, acc)
<<"\"", rest:bits>> -> {
use #(extracted, rest) <- try(string(rest, bytes_tree.new()))
separator(rest, stack, [#(Field(extracted), depth), ..acc])
}
<<"}", rest:bits>> -> {
let assert [ObjectField, ..stack] = stack
continue(rest, stack, acc)
}
<<>> -> Error(UnexpectedEnd)
_ -> Error(UnexpectedToken(buffer))
}
}
fn separator(buffer, stack, acc) {
case buffer {
<<"\r", rest:bits>>
| <<"\n", rest:bits>>
| <<" ", rest:bits>>
| <<"\t", rest:bits>> -> separator(rest, stack, acc)
<<":", rest:bits>> -> value(rest, stack, acc)
<<>> -> Error(UnexpectedEnd)
_ -> Error(UnexpectedToken(buffer))
}
}
fn string(buffer, acc) {
case buffer {
<<"\"", rest:bits>> -> {
let bytes = bytes_tree.to_bit_array(acc)
case bit_array.to_string(bytes) {
Ok(value) -> Ok(#(value, rest))
Error(Nil) -> Error(InvalidString(bytes))
}
}
<<"\\\"", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\"">>))
<<"\\\\", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\\">>))
<<"\\/", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"/">>))
<<"\\b", rest:bits>> -> string(rest, bytes_tree.append(acc, <<8>>))
<<"\\f", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\f">>))
<<"\\n", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\n">>))
<<"\\r", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\r">>))
<<"\\t", rest:bits>> -> string(rest, bytes_tree.append(acc, <<"\t">>))
<<"\\u", _rest:bits>> -> Error(UnexpectedToken(buffer))
<<"\\", _rest:bits>> -> Error(UnexpectedToken(buffer))
<<b, rest:bits>> -> string(rest, bytes_tree.append(acc, <<b>>))
<<>> -> Error(UnexpectedEnd)
_ -> Error(UnexpectedToken(buffer))
}
}
fn start_number(sign, first, rest, stack, acc) {
let #(n, _, rest) = digits(rest, first, 1)
case rest {
<<".", rest:bits>> -> start_decimal(sign, n, rest, stack, acc)
<<"e", rest:bits>> | <<"E", rest:bits>> ->
start_exponent(sign, n, #(0, 0), rest, stack, acc)
_ -> {
let n = case sign {
Positive -> n
Negative -> -n
}
continue(rest, stack, [#(Integer(n), list.length(stack)), ..acc])
}
}
}
fn start_decimal(sign, integer, rest, stack, acc) {
let #(decimal, size, rest) = digits(rest, 0, 0)
case size {
0 -> Error(MissingDigits)
_ ->
case rest {
<<"e", rest:bits>> | <<"E", rest:bits>> ->
start_exponent(sign, integer, #(decimal, size), rest, stack, acc)
_ -> {
let term =
Number(sign:, integer:, decimal: #(decimal, size), exponent: 0)
continue(rest, stack, [#(term, list.length(stack)), ..acc])
}
}
}
}
fn start_exponent(sign, integer, decimal, rest, stack, acc) {
let #(exp_sign, rest) = case rest {
<<"+", rest:bits>> -> #(Positive, rest)
<<"-", rest:bits>> -> #(Negative, rest)
_ -> #(Positive, rest)
}
let #(exponent, size, rest) = digits(rest, 0, 0)
case size {
0 -> Error(MissingDigits)
_ -> {
let exponent = case exp_sign {
Positive -> exponent
Negative -> -exponent
}
let term = Number(sign:, integer:, decimal:, exponent:)
continue(rest, stack, [#(term, list.length(stack)), ..acc])
}
}
}
fn digits(buffer, n, size) {
case buffer {
<<"1", rest:bits>> -> digits(rest, n * 10 + 1, size + 1)
<<"2", rest:bits>> -> digits(rest, n * 10 + 2, size + 1)
<<"3", rest:bits>> -> digits(rest, n * 10 + 3, size + 1)
<<"4", rest:bits>> -> digits(rest, n * 10 + 4, size + 1)
<<"5", rest:bits>> -> digits(rest, n * 10 + 5, size + 1)
<<"6", rest:bits>> -> digits(rest, n * 10 + 6, size + 1)
<<"7", rest:bits>> -> digits(rest, n * 10 + 7, size + 1)
<<"8", rest:bits>> -> digits(rest, n * 10 + 8, size + 1)
<<"9", rest:bits>> -> digits(rest, n * 10 + 9, size + 1)
<<"0", rest:bits>> -> digits(rest, n * 10 + 0, size + 1)
_ -> #(n, size, buffer)
}
}
fn continue(buffer, stack, acc) {
case buffer, stack {
<<"\r", rest:bits>>, _
| <<"\n", rest:bits>>, _
| <<" ", rest:bits>>, _
| <<"\t", rest:bits>>, _
-> continue(rest, stack, acc)
_, [] -> Ok(list.reverse(acc))
<<"]", rest:bits>>, [ArrayItem, ..stack] -> continue(rest, stack, acc)
<<",", rest:bits>>, [ArrayItem, ..] -> value(rest, stack, acc)
<<"}", rest:bits>>, [ObjectField, ..stack] -> continue(rest, stack, acc)
<<",", rest:bits>>, [ObjectField, ..] -> key(rest, stack, acc)
<<>>, _ -> Error(UnexpectedEnd)
_, _ -> Error(UnexpectedToken(buffer))
}
}