@@ -676,7 +676,124 @@ expr({map,Line,E0,Fs0}, Bs0, Ieval0) ->
676676 end , E , Fs ),
677677 {value ,Value ,merge_bindings (Bs2 , Bs1 , Ieval )};
678678
679- % % Record update
679+ % % Native record
680+ expr ({record_field ,_Anno ,{atom ,_ ,N },V0 }, Bs0 , Ieval ) ->
681+ {value ,V1 ,Bs1 } = expr (V0 , Bs0 , Ieval ),
682+ {value , {N ,V1 }, Bs1 };
683+ % % Native record field access
684+ expr ({record_field ,Line ,Src0 ,{M ,N },{atom ,_ ,K }}, Bs0 , Ieval ) ->
685+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
686+ case is_record (Src1 , M , N ) andalso records :is_exported (Src1 ) of
687+ true ->
688+ try records :get (K , Src1 ) of
689+ Val ->
690+ {value , Val , Bs }
691+ catch
692+ _ :_ ->
693+ exception (error , {badfield ,{{M ,N },K }}, Bs , Ieval # ieval {line = Line })
694+ end ;
695+ false ->
696+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
697+ end ;
698+ expr ({record_field ,Line ,Src0 ,[],{atom ,_ ,K }}, Bs0 , Ieval ) ->
699+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
700+ try records :get (K , Src1 ) of
701+ Val ->
702+ {value , Val , Bs }
703+ catch
704+ _ :_ ->
705+ case is_record (Src1 ) of
706+ true ->
707+ M = records :get_module (Src1 ),
708+ N = records :get_name (Src1 ),
709+ exception (error , {badfield ,{{M ,N },K }}, Bs , Ieval # ieval {line = Line });
710+ false ->
711+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
712+ end
713+ end ;
714+ expr ({record_field ,Line ,Src0 ,N ,{atom ,_ ,K }}, Bs0 , # ieval {module = M }= Ieval ) ->
715+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
716+ case is_record (Src1 , M , N ) of
717+ true ->
718+ try records :get (K , Src1 ) of
719+ Val ->
720+ {value , Val , Bs }
721+ catch
722+ _ :_ ->
723+ exception (error , {badfield ,{{M ,N },K }}, Bs , Ieval # ieval {line = Line })
724+ end ;
725+ false ->
726+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
727+ end ;
728+ % % Native record creation
729+ expr ({record ,Line ,{M ,N },Es }, Bs0 , Ieval ) ->
730+ try records :get_definition (M , N ) of
731+ {#{is_exported := false }, _ } ->
732+ exception (error , {badrecord ,{M , N }}, Bs0 , Ieval # ieval {line = Line });
733+ {Ops , Defs } ->
734+ {Vs , Bs } = eval_list (Es , Bs0 , Ieval # ieval {line = Line }),
735+ case native_record_init (Defs , Vs , []) of
736+ {novalue , K } ->
737+ exception (error , {novalue ,{{M ,N },K }}, Bs0 , Ieval # ieval {line = Line });
738+ {badfield , F } ->
739+ exception (error , {badfield ,{{M ,N },F }}, Bs0 , Ieval # ieval {line = Line });
740+ Acc ->
741+ R = records :create (M , N , Acc , Ops ),
742+ {value , R , Bs }
743+ end
744+ catch
745+ _ :_ ->
746+ exception (error , {badrecord ,{M , N }}, Bs0 , Ieval # ieval {line = Line })
747+ end ;
748+ expr ({record ,Line ,N ,Es }, Bs0 , # ieval {module = M }= Ieval ) when is_atom (N )->
749+ {Ops , Defs } = records :get_definition (M , N ),
750+ {Vs , Bs } = eval_list (Es , Bs0 , Ieval # ieval {line = Line }),
751+ Acc = native_record_init (Defs , Vs , []),
752+ R = records :create (M , N , Acc , Ops ),
753+ {value , R , Bs };
754+ % % Native record update
755+ expr ({record ,Line ,Src0 ,{M ,N },Es }, Bs0 , Ieval ) ->
756+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
757+ case is_record (Src1 , M , N ) andalso records :is_exported (Src1 ) of
758+ true ->
759+ {Vs ,Bs1 } = eval_list (Es , Bs , Ieval # ieval {line = Line }),
760+ Updates = #{K => V || {K , V } < :- Vs },
761+ R = records :update (Src1 , M , N , Updates ),
762+ {value , R , Bs1 };
763+ false ->
764+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
765+ end ;
766+ expr ({record ,Line ,Src0 ,[],Es }, Bs0 , # ieval {module = Mod }= Ieval ) ->
767+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
768+ case is_record (Src1 ) of
769+ true ->
770+ M = records :get_module (Src1 ),
771+ N = records :get_name (Src1 ),
772+ case records :is_exported (Src1 ) orelse Mod =:= M of
773+ true ->
774+ {Vs ,Bs } = eval_list (Es , Bs0 , Ieval # ieval {line = Line }),
775+ Updates = #{K => V || {K , V } < :- Vs },
776+ R = records :update (Src1 , M , N , Updates ),
777+ {value , R , Bs };
778+ false ->
779+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
780+ end ;
781+ false ->
782+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
783+ end ;
784+ expr ({record ,Line ,Src0 ,N ,Es }, Bs0 , # ieval {module = M }= Ieval ) when is_atom (N ) ->
785+ {value , Src1 , Bs } = expr (Src0 , Bs0 , Ieval ),
786+ case is_record (Src1 , M , N ) of
787+ true ->
788+ {Vs ,Bs } = eval_list (Es , Bs0 , Ieval # ieval {line = Line }),
789+ Updates = #{K => V || {K , V } < :- Vs },
790+ R = records :update (Src1 , M , N , Updates ),
791+ {value , R , Bs };
792+ false ->
793+ native_record_error (Line , Src0 , Src1 , Bs , Ieval )
794+ end ;
795+
796+ % % Tuple record update
680797expr ({record_update ,Line ,Es },Bs ,# ieval {level = Le }= Ieval0 ) ->
681798 % % Incr Level, we don't need to step (next) through temp
682799 % % variables creation and matching
@@ -1347,6 +1464,37 @@ is_generator_end([]) -> true;
13471464is_generator_end (<<>>) -> true ;
13481465is_generator_end (Other ) -> Other =:= #{}.
13491466
1467+ native_record_init ([{K , V }|Defs ], Vs , Acc ) ->
1468+ % % Fill in fields that have default values.
1469+ case lists :keyfind (K , 1 , Vs ) of
1470+ false ->
1471+ native_record_init (Defs , Vs , [{K , V }|Acc ]);
1472+ Res ->
1473+ native_record_init (Defs , Vs , [Res |Acc ])
1474+ end ;
1475+ native_record_init ([K |Defs ], Vs , Acc ) ->
1476+ % % Fill in fields with no default values.
1477+ case lists :keyfind (K , 1 , Vs ) of
1478+ false ->
1479+ {novalue , K };
1480+ Res ->
1481+ native_record_init (Defs , Vs , [Res |Acc ])
1482+ end ;
1483+ native_record_init ([], Vs , Acc ) ->
1484+ % % Report error for fields that don't exist in the definition.
1485+ case lists :partition (fun ({K , _ }) -> lists :keyfind (K , 1 , Acc ) =:= false end , Vs ) of
1486+ {[], _ } -> lists :reverse (Acc );
1487+ {[{F ,_ }|_ ], _ } ->{badfield , F }
1488+ end .
1489+
1490+ native_record_error (Line , Src0 , Src1 , Bs , Ieval ) ->
1491+ case Src0 of
1492+ {value , _ , Value } ->
1493+ exception (error , {badrecord ,Value }, Bs , Ieval # ieval {line = Line });
1494+ _ ->
1495+ exception (error , {badrecord ,Src1 }, Bs , Ieval # ieval {line = Line })
1496+ end .
1497+
13501498get_vars (Lit ) ->
13511499 get_vars (Lit , []).
13521500
@@ -1851,6 +1999,17 @@ guard_expr({dbg,_,self,[]}, _) ->
18511999guard_expr ({safe_bif ,_ ,erlang ,'not' ,As0 }, Bs ) ->
18522000 {values ,As } = guard_exprs (As0 , Bs ),
18532001 {value ,apply (erlang , 'not' , As )};
2002+ guard_expr ({record_guard_wildcard_field ,K ,Src0 }, Bs ) ->
2003+ {value ,Src1 } = guard_expr (Src0 , Bs ),
2004+ {value , records :get (K , Src1 )};
2005+ guard_expr ({record_guard_field ,{Mod ,Name },K ,Src0 }, Bs ) ->
2006+ {value ,Src1 } = guard_expr (Src0 , Bs ),
2007+ case is_record (Src1 , Mod , Name ) of
2008+ true ->
2009+ {value , records :get (K , Src1 )};
2010+ false ->
2011+ error (failed )
2012+ end ;
18542013guard_expr ({safe_bif ,_ ,Mod ,Func ,As0 }, Bs ) ->
18552014 {values ,As } = guard_exprs (As0 , Bs ),
18562015 {value ,apply (Mod , Func , As )};
@@ -1975,6 +2134,10 @@ match1({tuple,_,Elts}, Tuple, Bs, BBs)
19752134 match_tuple (Elts , Tuple , 1 , Bs , BBs );
19762135match1 ({map ,_ ,Fields }, Map , Bs , BBs ) when is_map (Map ) ->
19772136 match_map (Fields , Map , Bs , BBs );
2137+ match1 ({record ,_ ,_ ,_ }= R , Record , Bs , BBs ) when is_record (Record ) ->
2138+ match_record (R , Record , Bs , BBs );
2139+ match1 ({record_wildcard ,_ ,_ ,_ }= R , Record , Bs , BBs ) when is_record (Record ) ->
2140+ match_record (R , Record , Bs , BBs );
19782141match1 ({bin ,_ ,Fs }, B , Bs0 , BBs ) when is_bitstring (B ) ->
19792142 try eval_bits :match_bits (Fs , B , Bs0 , BBs ,
19802143 match_fun (BBs ),
@@ -2013,6 +2176,46 @@ match_map([{map_field_exact,_,K0,Pat}|Fs], Map, Bs0, BBs) ->
20132176match_map ([], _ , Bs , _BBs ) ->
20142177 {match ,Bs }.
20152178
2179+ match_record ({record_wildcard , _ , Mod , KVs }, R , Bs , BBs ) ->
2180+ case {KVs , records :get_module (R ), records :is_exported (R )} of
2181+ {[], _ , _ } ->
2182+ {match , Bs };
2183+ {_ , Mod , _ } ->
2184+ match_record_field (KVs , R , Bs , BBs );
2185+ {_ , _ , true } ->
2186+ match_record_field (KVs , R , Bs , BBs );
2187+ _ ->
2188+ throw (nomatch )
2189+ end ;
2190+ match_record ({record , _ , N , KVs }, R , Bs , BBs ) ->
2191+ case {N , records :get_module (R ), records :get_name (R )} of
2192+ {{Mod , Name }, Mod , Name } -> ok ;
2193+ {N , _ , N } -> ok ;
2194+ _ -> throw (nomatch )
2195+ end ,
2196+ % % Check if it's allowed to match fields.
2197+ case {KVs , records :is_exported (R ), N } of
2198+ {[], _ , _ } ->
2199+ {match , Bs };
2200+ {_ , true , _ } ->
2201+ match_record_field (KVs , R , Bs , BBs );
2202+ {_ , false , {_ , _ }} ->
2203+ throw (nomatch );
2204+ {_ , false , _ } ->
2205+ match_record_field (KVs , R , Bs , BBs )
2206+ end .
2207+
2208+ match_record_field ([{K , V }|KVs ], R , Bs0 , BBs ) ->
2209+ RV = try
2210+ records :get (K , R )
2211+ catch error :_ ->
2212+ throw (nomatch )
2213+ end ,
2214+ {match , Bs } = match1 (V , RV , Bs0 , BBs ),
2215+ match_record_field (KVs , R , Bs , BBs );
2216+ match_record_field ([], _ , Bs , _ ) ->
2217+ {match , Bs }.
2218+
20162219head_match ([Par |Pars ], [Arg |Args ], Bs0 , BBs ) ->
20172220 try match1 (Par , Arg , Bs0 , BBs ) of
20182221 {match ,Bs } -> head_match (Pars , Args , Bs , BBs )
0 commit comments