Skip to content

Commit 1cb7e56

Browse files
committed
Merge pull request #1564 from jakub-gonet/jgonet/is-record
Add `erlang:is_record/2` These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents ed6a158 + 1b64297 commit 1cb7e56

File tree

8 files changed

+93
-0
lines changed

8 files changed

+93
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ with nodejs and emscripten)
1515
- Added documentation and function specs for uart driver
1616
- Added `uart:read/2` with a timeout parameter.
1717
- Missing `erlang:is_function/2` BIF
18+
- Added `erlang:is_record/2`
1819

1920
### Fixed
2021

libs/estdlib/src/erlang.erl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
md5/1,
3838
is_map/1,
3939
is_map_key/2,
40+
is_record/2,
4041
map_size/1,
4142
map_get/2,
4243
monotonic_time/1,
@@ -396,6 +397,17 @@ apply(Function, Args) ->
396397
is_map(_Map) ->
397398
erlang:nif_error(undefined).
398399

400+
%%-----------------------------------------------------------------------------
401+
%% @param Term
402+
%% @param RecordTag atom representing tuple tag
403+
%%
404+
%% @doc Returns true if Term is a tuple and its first element is RecordTag, false otherwise.
405+
%% @end
406+
%%-----------------------------------------------------------------------------
407+
-spec is_record(Term :: term(), RecordTag :: atom()) -> boolean().
408+
is_record(_Term, _RecordTag) ->
409+
erlang:nif_error(undefined).
410+
399411
%%-----------------------------------------------------------------------------
400412
%% @param Map the map
401413
%% @returns the size of the map

src/libAtomVM/bif.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,18 @@ term bif_erlang_is_tuple_1(Context *ctx, uint32_t fail_label, term arg1)
241241
return term_is_tuple(arg1) ? TRUE_ATOM : FALSE_ATOM;
242242
}
243243

244+
term bif_erlang_is_record_2(Context *ctx, uint32_t fail_label, term arg1, term arg2)
245+
{
246+
UNUSED(ctx);
247+
VALIDATE_VALUE_BIF(fail_label, arg2, term_is_atom);
248+
if (!term_is_tuple(arg1) || term_get_tuple_arity(arg1) == 0) {
249+
return FALSE_ATOM;
250+
}
251+
252+
term tag = term_get_tuple_element(arg1, 0);
253+
return tag == arg2 ? TRUE_ATOM : FALSE_ATOM;
254+
}
255+
244256
term bif_erlang_is_map_1(Context *ctx, uint32_t fail_label, term arg1)
245257
{
246258
UNUSED(ctx);

src/libAtomVM/bif.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ term bif_erlang_is_number_1(Context *ctx, uint32_t fail_label, term arg1);
5858
term bif_erlang_is_pid_1(Context *ctx, uint32_t fail_label, term arg1);
5959
term bif_erlang_is_reference_1(Context *ctx, uint32_t fail_label, term arg1);
6060
term bif_erlang_is_tuple_1(Context *ctx, uint32_t fail_label, term arg1);
61+
term bif_erlang_is_record_2(Context *ctx, uint32_t fail_label, term arg1, term record_tag);
6162
term bif_erlang_is_map_1(Context *ctx, uint32_t fail_label, term arg1);
6263
term bif_erlang_is_map_key_2(Context *ctx, uint32_t fail_label, term arg1, term arg2);
6364

src/libAtomVM/bifs.gperf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ erlang:is_number/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlan
5353
erlang:is_pid/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlang_is_pid_1}
5454
erlang:is_reference/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlang_is_reference_1}
5555
erlang:is_tuple/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlang_is_tuple_1}
56+
erlang:is_record/2,{.bif.base.type = BIFFunctionType, .bif.bif2_ptr = bif_erlang_is_record_2}
5657
erlang:is_map/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlang_is_map_1}
5758
erlang:is_map_key/2, {.bif.base.type = BIFFunctionType, .bif.bif2_ptr = bif_erlang_is_map_key_2}
5859
erlang:not/1, {.bif.base.type = BIFFunctionType, .bif.bif1_ptr = bif_erlang_not_1}

tests/erlang_tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ compile_erlang(negatives2)
114114
compile_erlang(datetime)
115115
compile_erlang(test_system_time)
116116
compile_erlang(is_type)
117+
compile_erlang(is_record)
117118
compile_erlang(test_bitshift)
118119
compile_erlang(test_bitwise)
119120
compile_erlang(test_bitwise2)
@@ -903,6 +904,7 @@ add_custom_target(erlang_test_modules DEPENDS
903904

904905
is_fun_2_with_frozen.beam
905906
is_fun_2_with_frozen2.beam
907+
is_record.beam
906908

907909
function_reference_decode.beam
908910
makefunref.beam

tests/erlang_tests/is_record.erl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
%
2+
% This file is part of AtomVM.
3+
%
4+
% Copyright 2024 Tomasz Sobkiewicz <tomasz.sobkiewt>
5+
%
6+
% Licensed under the Apache License, Version 2.0 (the "License");
7+
% you may not use this file except in compliance with the License.
8+
% You may obtain a copy of the License at
9+
%
10+
% http://www.apache.org/licenses/LICENSE-2.0
11+
%
12+
% Unless required by applicable law or agreed to in writing, software
13+
% distributed under the License is distributed on an "AS IS" BASIS,
14+
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
% See the License for the specific language governing permissions and
16+
% limitations under the License.
17+
%
18+
% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
19+
%
20+
21+
-module(is_record).
22+
23+
-record(person, {id, name, age}).
24+
25+
-export([start/0, id/1, is_person/1, fail_with_badarg/1]).
26+
27+
-define(ID(Arg), ?MODULE:id(Arg)).
28+
29+
start() ->
30+
Mike = #person{
31+
id = 1,
32+
name = "Mike",
33+
age = 32
34+
},
35+
IsRecord = ?ID(fun erlang:is_record/2),
36+
true = IsRecord(?ID({person, 1, 2, 3}), ?ID(person)),
37+
true = erlang:is_record(?ID({person, 1, 2, 3}), ?ID(person)),
38+
true = erlang:is_record(?ID({person}), ?ID(person)),
39+
true = erlang:is_record(?ID(Mike), ?ID(person)),
40+
true = ?MODULE:is_person(?ID(Mike)),
41+
42+
false = ?MODULE:is_person(?ID({tuple, 1, 2})),
43+
false = erlang:is_record(?ID(Mike), ?ID(foo)),
44+
false = erlang:is_record(?ID({person, 1, 2, 3}), ?ID(foo)),
45+
false = erlang:is_record(?ID({}), ?ID(person)),
46+
false = erlang:is_record(?ID([]), ?ID(person)),
47+
ok = fail_with_badarg(fun() -> erlang:is_record(?ID(Mike), ?ID(1)) end),
48+
ok = fail_with_badarg(fun() -> erlang:is_record(?ID({}), ?ID(1)) end),
49+
0.
50+
51+
id(T) ->
52+
T.
53+
54+
is_person(T) when is_record(T, person) -> true;
55+
is_person(_X) -> false.
56+
57+
fail_with_badarg(Fun) ->
58+
try Fun() of
59+
Ret -> {unexpected, Ret}
60+
catch
61+
error:badarg -> ok;
62+
C:E -> {unexpected, C, E}
63+
end.

tests/test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ struct Test tests[] = {
438438
TEST_CASE_EXPECTED(boxed_is_not_float, 16),
439439
TEST_CASE_EXPECTED(float_is_float, 32),
440440
TEST_CASE_EXPECTED(float_is_number, 32),
441+
TEST_CASE(is_record),
441442
TEST_CASE(fconv_fail_invalid),
442443

443444
TEST_CASE_EXPECTED(float2bin, 31),

0 commit comments

Comments
 (0)