# How to evaluate expressions containing record reference?

**URL:** <https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273>\
**Category:** Questions / Help\
**Tags:** erlang\
**Created:** [February 7, 2024, 4:03pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273 "2024-02-07T16:03:50Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![etnt](https://erlangforums.com/user_avatar/erlangforums.com/etnt/32/892_2.png) [@etnt](https://erlangforums.com/u/etnt)\
**Post date:** [February 7, 2024, 4:03pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/1 "2024-02-07T16:03:50Z")

</div>

Hi,

How can I evaluate expressions such as: “X = P#person.age.” using something like erl\_eval:exprs and friends?

Sort of like this (non-working code):

```erlang
my_eval() ->
    PersonDef = {attribute,38,record,                                                                                                                                                                              
                    {person,[{record_field,38,{atom,38,name}},                                                                                                                                              
                             {record_field,38,{atom,38,age}}]}},
                        
    RecordDefs = [{person, 38, PersonDef}],

    Person = #person{name = "John", age = 30},
    Bindings0 = erl_eval:new_bindings(),
    Bindings = erl_eval:add_binding('P', Person, Bindings0),

    eval_exprs("X = P#person.age.", Bindings, RecordDefs).

    eval_exprs(Expression, Bindings, RecordDefs) ->
    
        %% Parse the expression
        {ok, Tokens, _} = erl_scan:string(Expression),
        {ok, [Expr]} = erl_parse:parse_exprs(Tokens),
    
        %% Evaluate the expression
        case erl_eval:exprs([Expr], Bindings, RecordDefs) of
            {value, Value, NewBindings} -> {Value, NewBindings};
            Error -> Error
        end.

```

---

<div class="post-metadata">

**Author:** ![mmin](https://erlangforums.com/user_avatar/erlangforums.com/mmin/32/2193_2.png) [@mmin](https://erlangforums.com/u/mmin)\
**Post date:** [February 7, 2024, 4:22pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/2 "2024-02-07T16:22:53Z")

</div>

I don’t think that’s possible, but what is possible is to use [erl\_expand\_records](https://www.erlang.org/doc/man/erl_expand_records#module-2) module to expand records to tuples. It will return modified `abstract_form()`s and you can act like that is what you originally parsed.

---

<div class="post-metadata">

**Author:** ![williamthome](https://erlangforums.com/user_avatar/erlangforums.com/williamthome/32/471_2.png) [@williamthome](https://erlangforums.com/u/williamthome)\
**Post date:** [February 7, 2024, 4:46pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/3 "2024-02-07T16:46:48Z")

</div>

I believe there is no easy way to achieve that.  
Maybe you can try [erl\_eval\_records](https://github.com/petrkozorezov/erl_eval_records/tree/master) lib.

---

<div class="post-metadata">

**Author:** ![williamthome](https://erlangforums.com/user_avatar/erlangforums.com/williamthome/32/471_2.png) [@williamthome](https://erlangforums.com/u/williamthome)\
**Post date:** [February 7, 2024, 5:04pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/4 "2024-02-07T17:04:04Z")

</div>

Or change your code to call a function

```erlang
-module(my_person).
-export([get_person_age/1, my_eval/0]).

-record(person, {name, age}).

get_person_age(#person{age = Age}) ->
    Age.

my_eval() ->
    Person = #person{name = "John", age = 30},
    Bindings0 = erl_eval:new_bindings(),
    Bindings = erl_eval:add_binding('P', Person, Bindings0),
    eval_exprs("X = my_person:get_person_age(P).", Bindings). %% <-- Uses a function

eval_exprs(Expression, Bindings) ->

    %% Parse the expression
    {ok, Tokens, _} = erl_scan:string(Expression),
    {ok, [Expr]} = erl_parse:parse_exprs(Tokens),

    %% Evaluate the expression
    case erl_eval:exprs([Expr], Bindings) of
        {value, Value, NewBindings} -> {Value, NewBindings};
        Error -> Error
    end.

```

Result

```erlang
1> my_person:my_eval().
{30,[{'P',{person,"John",30}},{'X',30}]}

```

---

<div class="post-metadata">

**Author:** ![etnt](https://erlangforums.com/user_avatar/erlangforums.com/etnt/32/892_2.png) [@etnt](https://erlangforums.com/u/etnt)\
**Post date:** [February 9, 2024, 10:52am UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/5 "2024-02-09T10:52:09Z")

</div>

Mm…thanks for the suggestions.

A pity that eval\_exprs/N can’t handle it, perhaps I could wish for a feature enhancement in some future release… 😛

---

<div class="post-metadata">

**Author:** ![williamthome](https://erlangforums.com/user_avatar/erlangforums.com/williamthome/32/471_2.png) [@williamthome](https://erlangforums.com/u/williamthome)\
**Post date:** [February 9, 2024, 10:20pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/6 "2024-02-09T22:20:24Z")

</div>

Using the `erl_expand_records` that @mmin mentioned, I’ve ended up doing something that can maybe help you. `erl_expand_records` expects record attributes, and what it expands are functions, so we need to wrap the parsed forms into a function.

Take this (tricky) example (it needs to be improved using `erl_syntax`):

```erlang
-module(eval).

-export([string/3, record_attribute/2]).

string(String, Bindings, HeaderForms) ->
    ExprForms = wrap(expr_forms(String)),
    Forms = lists:last(erl_expand_records:module(HeaderForms ++ ExprForms, [])),
    erl_eval:expr(unwrap(Forms), Bindings).

record_attribute(Name, Fields0) when is_atom(Name), is_list(Fields0) ->
    Fields1 = [atom_to_binary(Field) || Field <- Fields0],
    Fields = lists:join(", ", Fields1),
    IOList = io_lib:format("-record(~s, {~s}).", [Name, Fields]),
    merl:quote(iolist_to_binary(IOList)).

%% Internal functions

expr_forms(String) ->
    {ok, Tokens, _} = erl_scan:string(String),
    {ok, Forms} = erl_parse:parse_exprs(Tokens),
    Forms.

wrap(Expr) ->
    [{function, 1, {atom, 1, foo}, 1, [{clause, 1, [], [], Expr}]}].

unwrap({function, 1, {atom, 1, foo}, 1, [{clause, 1, [], [], [Expr]}]}) ->
    Expr.

```

Result:

```erlang
1> HeaderForms = [eval:record_attribute(person, [name, age])].
[{attribute,1,record,
            {person,[{record_field,1,{atom,1,name}},
                     {record_field,1,{atom,1,age}}]}}]
2> eval:string("X = P#person.age.", #{'P' => {person, "John", 30}}, HeaderForms).
{value,30,#{'X' => 30,'P' => {person,"John",30},rec0 => 30}}

```

Hope it can help you.

---

<div class="post-metadata">

**Author:** ![etnt](https://erlangforums.com/user_avatar/erlangforums.com/etnt/32/892_2.png) [@etnt](https://erlangforums.com/u/etnt)\
**Post date:** [February 12, 2024, 10:41pm UTC](https://erlangforums.com/t/how-to-evaluate-expressions-containing-record-reference/3273/7 "2024-02-12T22:41:42Z")

</div>

Thanks!  
I’ll have a look.
