Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: erlef/setup-beam@v1
with:
otp-version: "26.0.2"
gleam-version: "1.5.1"
gleam-version: "1.9.1"
rebar3-version: "3"
# elixir-version: "1.15.4"
- run: gleam deps download
Expand Down
6 changes: 2 additions & 4 deletions gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ description = "Pretty print values with style!"
licences = ["Apache-2.0"]
repository = { type = "github", user = "MystPi", repo = "pprint" }

internal_modules = [
"pprint/decoder"
]
internal_modules = ["pprint/decoder"]

[dependencies]
gleam_stdlib = "~> 0.34 or ~> 1.0"
gleam_stdlib = ">= 0.50.0 and < 2.0.0"
glam = "~> 2.0"

[dev-dependencies]
Expand Down
28 changes: 15 additions & 13 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@

packages = [
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
{ name = "birdie", version = "1.1.4", build_tools = ["gleam"], requirements = ["argv", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "67E5D53B85540EDC6FAC738D7A4A2EEAA0C4920230AFFF4FA76C63670C057E5A" },
{ name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" },
{ name = "glam", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "66EC3BCD632E51EED029678F8DF419659C1E57B1A93D874C5131FE220DFAD2B2" },
{ name = "glance", version = "0.11.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "8F3314D27773B7C3B9FB58D8C02C634290422CE531988C0394FA0DF8676B964D" },
{ name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" },
{ name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" },
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
{ name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" },
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
{ name = "glexer", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "BD477AD657C2B637FEF75F2405FAEFFA533F277A74EF1A5E17B55B1178C228FB" },
{ name = "birdie", version = "1.2.6", build_tools = ["gleam"], requirements = ["argv", "edit_distance", "filepath", "glance", "gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "justin", "rank", "simplifile", "term_size", "trie_again"], otp_app = "birdie", source = "hex", outer_checksum = "1363F4C7E7433A4A8350CC682BCDDBA5BBC6F66C94EFC63BC43025F796C4F6D0" },
{ name = "edit_distance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "edit_distance", source = "hex", outer_checksum = "A1E485C69A70210223E46E63985FA1008B8B2DDA9848B7897469171B29020C05" },
{ name = "filepath", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "65F51013BCF78A603AFFD7992EF1CC6ECA96C74038EB48887F656DE44DBC1902" },
{ name = "glam", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glam", source = "hex", outer_checksum = "4932A2D139AB0389E149396407F89654928D7B815E212BB02F13C66F53B1BBA1" },
{ name = "glance", version = "2.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "106111453AE9BA959184302B7DADF2E8CF322B27A7CB68EE78F3EE43FEACCE2C" },
{ name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
{ name = "gleam_community_colour", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "FDD6AC62C6EC8506C005949A4FCEF032038191D5EAAEC3C9A203CD53AE956ACA" },
{ name = "gleam_erlang", version = "0.34.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "0C38F2A128BAA0CEF17C3000BD2097EB80634E239CE31A86400C4416A5D0FDCC" },
{ name = "gleam_json", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "C55C5C2B318533A8072D221C5E06E5A75711C129E420DD1CE463342106012E5D" },
{ name = "gleam_regexp", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "7F5E0C0BBEB3C58E57C9CB05FA9002F970C85AD4A63BA1E55CBCB35C15809179" },
{ name = "gleam_stdlib", version = "0.58.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "091F2D2C4A3A4E2047986C47E2C2C9D728A4E068ABB31FDA17B0D347E6248467" },
{ name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" },
{ name = "glexer", version = "2.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "5C235CBDF4DA5203AD5EAB1D6D8B456ED8162C5424FE2309CFFB7EF438B7C269" },
{ name = "justin", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "justin", source = "hex", outer_checksum = "7FA0C6DB78640C6DC5FBFD59BF3456009F3F8B485BF6825E97E1EB44E9A1E2CD" },
{ name = "rank", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "rank", source = "hex", outer_checksum = "5660E361F0E49CBB714CC57CC4C89C63415D8986F05B2DA0C719D5642FAD91C9" },
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
{ name = "thoas", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "540C8CB7D9257F2AD0A14145DC23560F91ACDCA995F0CCBA779EB33AF5D859D1" },
{ name = "simplifile", version = "2.2.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C88E0EE2D509F6D86EB55161D631657675AA7684DAB83822F7E59EB93D9A60E3" },
{ name = "term_size", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "term_size", source = "hex", outer_checksum = "D00BD2BC8FB3EBB7E6AE076F3F1FF2AC9D5ED1805F004D0896C784D06C6645F1" },
{ name = "trie_again", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "trie_again", source = "hex", outer_checksum = "5B19176F52B1BD98831B57FDC97BD1F88C8A403D6D8C63471407E78598E27184" },
]

Expand Down
65 changes: 39 additions & 26 deletions src/pprint/decoder.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/dict.{type Dict}
import gleam/dynamic.{type Dynamic}
import gleam/dynamic/decode
import gleam/result
import gleam/string

Expand Down Expand Up @@ -27,42 +28,54 @@ pub type Field {
// ---- DECODERS ---------------------------------------------------------------

pub fn classify(value: Dynamic) -> Type {
let assert Ok(t) = decode_type(value)
let assert Ok(t) = decode.run(value, type_decoder())
t
}

/// This decoder will always be `Ok`. It returns `Result` so that it is compatible
/// with other decoders.
///
fn decode_type(value: Dynamic) -> Result(Type, List(dynamic.DecodeError)) {
use <- result.lazy_or(result.map(dynamic.int(value), TInt))
use <- result.lazy_or(result.map(dynamic.float(value), TFloat))
use <- result.lazy_or(result.map(dynamic.string(value), TString))
use <- result.lazy_or(result.map(dynamic.bool(value), TBool))
use <- result.lazy_or(result.map(decode_nil(value), fn(_) { TNil }))
use <- result.lazy_or(result.map(dynamic.bit_array(value), TBitArray))
use <- result.lazy_or(decode_custom_type(value))
use <- result.lazy_or(result.map(decode_tuple(value), TTuple))
use <- result.lazy_or(result.map(dynamic.shallow_list(value), TList))
use <- result.lazy_or(result.map(
dynamic.dict(decode_type, decode_type)(value),
TDict,
))
// Anything else we just inspect. This could be a function or an external object
// or type from the runtime.
Ok(TForeign(string.inspect(value)))
/// This decoder will always return `Ok`, as it ends with a catch-all
/// pattern returning a `TForeign`.
///
fn type_decoder() -> decode.Decoder(Type) {
use <- decode.recursive
decode.one_of(decode.map(decode.int, TInt), [
decode.map(decode.float, TFloat),
decode.map(decode.float, TFloat),
decode.map(decode.string, TString),
decode.map(decode.bool, TBool),
decode.map(nil(), fn(_) { TNil }),
decode.map(decode.bit_array, TBitArray),
custom_type(),
decode.map(tuple(), TTuple),
decode.map(decode.list(decode.dynamic), TList),
decode.map(decode.dict(type_decoder(), type_decoder()), TDict),
decode.map(decode.dynamic, fn(value) { TForeign(string.inspect(value)) }),
])
}

fn tuple() -> decode.Decoder(List(Dynamic)) {
decode.new_primitive_decoder("Tuple", fn(dynamic) {
result.replace_error(decode_tuple(dynamic), [])
})
}

fn custom_type() -> decode.Decoder(Type) {
decode.new_primitive_decoder("CustomType", fn(dynamic) {
result.replace_error(decode_custom_type(dynamic), TCustom("", []))
})
}

fn nil() -> decode.Decoder(Nil) {
decode.new_primitive_decoder("Nil", decode_nil)
}

@external(erlang, "pprint_ffi", "decode_custom_type")
@external(javascript, "../pprint_ffi.mjs", "decode_custom_type")
fn decode_custom_type(value: Dynamic) -> Result(Type, List(dynamic.DecodeError))
fn decode_custom_type(value: Dynamic) -> Result(Type, Nil)

@external(erlang, "pprint_ffi", "decode_tuple")
@external(javascript, "../pprint_ffi.mjs", "decode_tuple")
fn decode_tuple(
value: Dynamic,
) -> Result(List(Dynamic), List(dynamic.DecodeError))
fn decode_tuple(value: Dynamic) -> Result(List(Dynamic), Nil)

@external(erlang, "pprint_ffi", "decode_nil")
@external(javascript, "../pprint_ffi.mjs", "decode_nil")
fn decode_nil(value: Dynamic) -> Result(Nil, List(dynamic.DecodeError))
fn decode_nil(value: Dynamic) -> Result(Nil, Nil)
33 changes: 17 additions & 16 deletions src/pprint_ffi.erl
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
decode_nil(X) ->
case X of
nil -> {ok, nil};
_ -> decode_error("Nil", X)
_ -> {error, nil}
end.

decode_tuple(X) ->
case X of
Tuple when is_tuple(Tuple) -> {ok, tuple_to_list(Tuple)};
_ -> decode_error("Tuple", X)
_ -> {error, nil}
end.

decode_custom_type(X) ->
Expand All @@ -23,28 +23,28 @@ decode_custom_type(X) ->
Atom when is_atom(Atom) ->
case inspect_maybe_gleam_atom(erlang:atom_to_binary(Atom), none, <<>>) of
{ok, AtomName} -> {ok, {t_custom, AtomName, []}};
{error, nil} -> decode_error("CustomType", X)
{error, nil} -> {error, nil}
end;
% Variants with fields are encoded as tuples where the first items is an
% atom with the variant's name.
Tuple when is_tuple(Tuple) ->
case tuple_to_list(Tuple) of
[Atom | Elements] when is_atom(Atom) ->
case inspect_maybe_gleam_atom(erlang:atom_to_binary(Atom), none, <<>>) of
{ok, AtomName} -> {ok, {t_custom, AtomName, lists:map(fun(E) -> {positional, E} end, Elements)}};
{error, nil} -> decode_error("CustomType", X)
{ok, AtomName} ->
{ok,
{t_custom, AtomName,
lists:map(fun(E) -> {positional, E} end, Elements)}};
{error, nil} ->
{error, nil}
end;
_ -> decode_error("CustomType", X)
_ ->
{error, nil}
end;
_ -> decode_error("CustomType", X)
_ ->
{error, nil}
end.

decode_error(Expected, Got) ->
ExpectedString = list_to_binary(Expected),
GotString = gleam_stdlib:classify_dynamic(Got),
DecodeError = {decode_error, ExpectedString, GotString, []},
{error, [DecodeError]}.

% This is copy pasted from gleam's stdlib and performs some additional checks to
% make sure the given atom is a gleam's custom type atom. Stdlib doesn't export
% it so I had to copy it.
Expand All @@ -58,10 +58,11 @@ inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, none, _) ->
{error, nil};
inspect_maybe_gleam_atom(<<"_">>, _PrevChar, _Acc) ->
{error, nil};
inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) ->
inspect_maybe_gleam_atom(<<"_", _Rest/binary>>, $_, _Acc) ->
{error, nil};
inspect_maybe_gleam_atom(<<First, _Rest/binary>>, _PrevChar, _Acc)
when not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First)) ->
inspect_maybe_gleam_atom(<<First, _Rest/binary>>, _PrevChar, _Acc) when
not (?is_lowercase_char(First) orelse ?is_underscore_char(First) orelse ?is_digit_char(First))
->
{error, nil};
inspect_maybe_gleam_atom(<<First, Rest/binary>>, none, Acc) ->
inspect_maybe_gleam_atom(Rest, First, <<Acc/binary, (uppercase(First))>>);
Expand Down
22 changes: 4 additions & 18 deletions src/pprint_ffi.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import * as $stdlib from '../gleam_stdlib/gleam_stdlib.mjs';
import * as $dynamic from '../gleam_stdlib/gleam/dynamic.mjs';
import * as $gleam from './gleam.mjs';
import * as $decoder from './pprint/decoder.mjs';

function decoder_error(expected, got) {
return decoder_error_no_classify(expected, $stdlib.classify_dynamic(got));
}

function decoder_error_no_classify(expected, got) {
return new $gleam.Error(
$gleam.List.fromArray([
new $dynamic.DecodeError(expected, got, $gleam.toList([])),
])
);
}

export function decode_custom_type(value) {
if (value instanceof $gleam.CustomType) {
const name = value.constructor.name;
Expand All @@ -27,15 +13,15 @@ export function decode_custom_type(value) {
return new $gleam.Ok(new $decoder.TCustom(name, $gleam.toList(fields)));
}

return decoder_error('CustomType', value);
return new $gleam.Error(undefined);
}

export function decode_tuple(value) {
if (Array.isArray(value)) return new $gleam.Ok($gleam.toList(value));
return decoder_error('Tuple', value);
return new $gleam.Error(undefined);
}

export function decode_nil(value) {
if (value === undefined) return new $gleam.Ok();
return decoder_error('Nil', value);
if (value === undefined) return new $gleam.Ok(undefined);
return new $gleam.Error(undefined);
}