Skip to content

Commit

Permalink
Elixir library: make inspect() more similar to Elixir one
Browse files Browse the repository at this point in the history
inspect() now supports lists, improper lists, it adds quotes to
printable lists, etc...

Signed-off-by: Davide Bettio <[email protected]>
  • Loading branch information
bettio committed Sep 24, 2024
1 parent 7c0e0dd commit 119a058
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ instead
- Fix handling of large literal indexes
- `unicode:characters_to_list`: fixed bogus out_of_memory error on some platforms such as ESP32
- Fix crash in Elixir library when doing `inspect(:atom)`
- General inspect() compliance with Elixir behavior (but there are still some minor differences)

## [0.6.4] - 2024-08-18

Expand Down
37 changes: 33 additions & 4 deletions libs/exavmlib/lib/Kernel.ex
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ defmodule Kernel do
:erlang.integer_to_binary(t)

t when is_list(t) ->
# TODO: escape unprintable lists
:erlang.list_to_binary(t)
if is_printable_list(t) do
str = :erlang.list_to_binary(t)
<<?'::utf8, str::binary, ?'::utf8>>
else
[?[ | t |> inspect_join(?])]
|> :erlang.list_to_binary()
end

t when is_pid(t) ->
:erlang.pid_to_list(t)
Expand All @@ -65,14 +70,14 @@ defmodule Kernel do

t when is_binary(t) ->
# TODO: escape unprintable binaries
t
<<?"::utf8, t::binary, ?"::utf8>>

t when is_reference(t) ->
:erlang.ref_to_list(t)
|> :erlang.list_to_binary()

t when is_float(t) ->
:erlang.float_to_binary(t)
:erlang.float_to_binary(term, [{:decimals, 17}, :compact])

t when is_map(t) ->
[?%, ?{ | t |> inspect_kv() |> join(?})]
Expand All @@ -88,6 +93,10 @@ defmodule Kernel do
[inspect(e), last]
end

defp inspect_join([h | e], last) when not is_list(e) do
[inspect(h), " | ", inspect(e), last]
end

defp inspect_join([h | t], last) do
[inspect(h), ?,, ?\s | inspect_join(t, last)]
end
Expand Down Expand Up @@ -140,6 +149,26 @@ defmodule Kernel do
end
end

defp is_printable_list([]), do: false

defp is_printable_list([char]) do
is_printable_ascii(char)
end

defp is_printable_list([char | t]) do
if is_printable_ascii(char) do
is_printable_list(t)
else
false
end
end

defp is_printable_list(_any), do: false

defp is_printable_ascii(char) do
is_integer(char) and char >= 32 and char < 127 and char != ?'
end

@doc """
Returns the biggest of the two given terms according to
Erlang's term ordering.
Expand Down
44 changes: 44 additions & 0 deletions tests/libs/exavmlib/Tests.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
#

defmodule Tests do

# defstruct [
# :field1,
# field2: 42
# ]

@compile {:no_warn_undefined, :undef}

def start() do
Expand Down Expand Up @@ -244,10 +250,48 @@ defmodule Tests do
":アトム" = inspect(:アトム)
"Test" = inspect(Test)

"5" = inspect(5)
"5.0" = inspect(5.0)

~s["hello"] = inspect("hello")
~s["アトム"] = inspect("アトム")

"[]" = inspect([])
"[0]" = inspect([0])
"[9, 10]" = inspect([9, 10])
~s'["test"]' = inspect(["test"])
"'hello'" = inspect('hello')
"[127]" = inspect([127])
"[104, 101, 108, 108, 248]" = inspect('hellø')

~s([5 | "hello"]) = inspect([5 | "hello"])

"{}" = inspect({})
"{1, 2}" = inspect({1, 2})
"{:test, 1}" = inspect({:test, 1})

"%{}" = inspect(%{})
either("%{a: 1, b: 2}", "%{b: 2, a: 1}", inspect(%{a: 1, b: 2}))
either(~s[%{"a" => 1, "b" => 2}], ~s[%{"b" => 2, "a" => 1}], inspect(%{"a" => 1, "b" => 2}))

# TODO: structs are not yet supported
# either(
# ~s[%#{__MODULE__}{field1: nil, field2: 42}],
# ~s[%#{__MODULE__}{field2: 42, field1: nil}],
# inspect(%__MODULE__{})
# )

:ok
end

defp fact(n) when n < 0, do: :test
defp fact(0), do: 1
defp fact(n), do: fact(n - 1) * n

def either(a, b, value) do
case value do
^a -> a
^b -> b
end
end
end

0 comments on commit 119a058

Please sign in to comment.