Skip to content

Commit 36cb1b8

Browse files
committed
Elixir library: make inspect() more similar to Elixir one
inspect() now supports lists, improper lists, it adds quotes to printable lists, etc... Signed-off-by: Davide Bettio <davide@uninstall.it>
1 parent 5caab38 commit 36cb1b8

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ instead
3939
- Fix handling of large literal indexes
4040
- `unicode:characters_to_list`: fixed bogus out_of_memory error on some platforms such as ESP32
4141
- Fix crash in Elixir library when doing `inspect(:atom)`
42+
- General inspect() compliance with Elixir behavior (but there are still some minor differences)
4243

4344
## [0.6.4] - 2024-08-18
4445

libs/exavmlib/lib/Kernel.ex

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,13 @@ defmodule Kernel do
4848
:erlang.integer_to_binary(t)
4949

5050
t when is_list(t) ->
51-
# TODO: escape unprintable lists
52-
:erlang.list_to_binary(t)
51+
if is_printable_list(t) do
52+
str = :erlang.list_to_binary(t)
53+
<<?'::utf8, str::binary, ?'::utf8>>
54+
else
55+
[?[ | t |> inspect_join(?])]
56+
|> :erlang.list_to_binary()
57+
end
5358

5459
t when is_pid(t) ->
5560
:erlang.pid_to_list(t)
@@ -64,15 +69,19 @@ defmodule Kernel do
6469
|> :erlang.list_to_binary()
6570

6671
t when is_binary(t) ->
67-
# TODO: escape unprintable binaries
68-
t
72+
if is_printable_binary(t) do
73+
<<?"::utf8, t::binary, ?"::utf8>>
74+
else
75+
["<<" | t |> :erlang.binary_to_list() |> inspect_join(">>")]
76+
|> :erlang.list_to_binary()
77+
end
6978

7079
t when is_reference(t) ->
7180
:erlang.ref_to_list(t)
7281
|> :erlang.list_to_binary()
7382

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

7786
t when is_map(t) ->
7887
[?%, ?{ | t |> inspect_kv() |> join(?})]
@@ -88,6 +97,10 @@ defmodule Kernel do
8897
[inspect(e), last]
8998
end
9099

100+
defp inspect_join([h | e], last) when not is_list(e) do
101+
[inspect(h), " | ", inspect(e), last]
102+
end
103+
91104
defp inspect_join([h | t], last) do
92105
[inspect(h), ?,, ?\s | inspect_join(t, last)]
93106
end
@@ -140,6 +153,34 @@ defmodule Kernel do
140153
end
141154
end
142155

156+
defp is_printable_list([]), do: false
157+
158+
defp is_printable_list([char]) do
159+
is_printable_ascii(char)
160+
end
161+
162+
defp is_printable_list([char | t]) do
163+
if is_printable_ascii(char) do
164+
is_printable_list(t)
165+
else
166+
false
167+
end
168+
end
169+
170+
defp is_printable_list(_any), do: false
171+
172+
defp is_printable_ascii(char) do
173+
is_integer(char) and char >= 32 and char < 127 and char != ?'
174+
end
175+
176+
defp is_printable_binary(<<>>), do: true
177+
178+
defp is_printable_binary(<<char::utf8, rest::binary>>) when char >= 32 do
179+
is_printable_binary(rest)
180+
end
181+
182+
defp is_printable_binary(_any), do: false
183+
143184
@doc """
144185
Returns the biggest of the two given terms according to
145186
Erlang's term ordering.

tests/libs/exavmlib/Tests.ex

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#
2020

2121
defmodule Tests do
22+
# defstruct [
23+
# :field1,
24+
# field2: 42
25+
# ]
26+
2227
@compile {:no_warn_undefined, :undef}
2328

2429
def start() do
@@ -244,10 +249,53 @@ defmodule Tests do
244249
":アトム" = inspect(:アトム)
245250
"Test" = inspect(Test)
246251

252+
"5" = inspect(5)
253+
"5.0" = inspect(5.0)
254+
255+
~s[""] = inspect("")
256+
~s["hello"] = inspect("hello")
257+
~s["アトム"] = inspect("アトム")
258+
259+
"<<10>>" = inspect("\n")
260+
"<<0, 1, 2, 3>>" = inspect(<<0, 1, 2, 3>>)
261+
"<<195, 168, 0>>" = inspect(<<195, 168, 0>>)
262+
263+
"[]" = inspect([])
264+
"[0]" = inspect([0])
265+
"[9, 10]" = inspect([9, 10])
266+
~s'["test"]' = inspect(["test"])
267+
"'hello'" = inspect('hello')
268+
"[127]" = inspect([127])
269+
"[104, 101, 108, 108, 248]" = inspect('hellø')
270+
271+
~s([5 | "hello"]) = inspect([5 | "hello"])
272+
273+
"{}" = inspect({})
274+
"{1, 2}" = inspect({1, 2})
275+
"{:test, 1}" = inspect({:test, 1})
276+
277+
"%{}" = inspect(%{})
278+
either("%{a: 1, b: 2}", "%{b: 2, a: 1}", inspect(%{a: 1, b: 2}))
279+
either(~s[%{"a" => 1, "b" => 2}], ~s[%{"b" => 2, "a" => 1}], inspect(%{"a" => 1, "b" => 2}))
280+
281+
# TODO: structs are not yet supported
282+
# either(
283+
# ~s[%#{__MODULE__}{field1: nil, field2: 42}],
284+
# ~s[%#{__MODULE__}{field2: 42, field1: nil}],
285+
# inspect(%__MODULE__{})
286+
# )
287+
247288
:ok
248289
end
249290

250291
defp fact(n) when n < 0, do: :test
251292
defp fact(0), do: 1
252293
defp fact(n), do: fact(n - 1) * n
294+
295+
def either(a, b, value) do
296+
case value do
297+
^a -> a
298+
^b -> b
299+
end
300+
end
253301
end

0 commit comments

Comments
 (0)