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(<>) } 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)) <> -> string(rest, bytes_tree.append(acc, <>)) <<>> -> 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)) } }