diff options
Diffstat (limited to 'src/vhdl/vhdl-sem_stmts.adb')
-rw-r--r-- | src/vhdl/vhdl-sem_stmts.adb | 2183 |
1 files changed, 2183 insertions, 0 deletions
diff --git a/src/vhdl/vhdl-sem_stmts.adb b/src/vhdl/vhdl-sem_stmts.adb new file mode 100644 index 000000000..9a616896a --- /dev/null +++ b/src/vhdl/vhdl-sem_stmts.adb @@ -0,0 +1,2183 @@ +-- Semantic analysis. +-- Copyright (C) 2002, 2003, 2004, 2005 Tristan Gingold +-- +-- GHDL is free software; you can redistribute it and/or modify it under +-- the terms of the GNU General Public License as published by the Free +-- Software Foundation; either version 2, or (at your option) any later +-- version. +-- +-- GHDL is distributed in the hope that it will be useful, but WITHOUT ANY +-- WARRANTY; without even the implied warranty of MERCHANTABILITY or +-- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +-- for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with GHDL; see the file COPYING. If not, write to the Free +-- Software Foundation, 59 Temple Place - Suite 330, Boston, MA +-- 02111-1307, USA. +with Errorout; use Errorout; +with Types; use Types; +with Flags; use Flags; +with Vhdl.Sem_Specs; use Vhdl.Sem_Specs; +with Std_Package; use Std_Package; +with Vhdl.Sem; use Vhdl.Sem; +with Vhdl.Sem_Decls; use Vhdl.Sem_Decls; +with Vhdl.Sem_Expr; use Vhdl.Sem_Expr; +with Vhdl.Sem_Names; use Vhdl.Sem_Names; +with Vhdl.Sem_Scopes; use Vhdl.Sem_Scopes; +with Vhdl.Sem_Types; +with Vhdl.Sem_Psl; +with Std_Names; +with Evaluation; use Evaluation; +with Iirs_Utils; use Iirs_Utils; +with Xrefs; use Xrefs; + +package body Vhdl.Sem_Stmts is + -- Process is the scope, this is also the process for which drivers can + -- be created. + -- Note: FIRST_STMT is the first statement, which can be get by: + -- get_sequential_statement_chain (usual) + -- get_associated_chain (for case statement). + procedure Sem_Sequential_Statements_Internal (First_Stmt : Iir); + + -- Access to the current subprogram or process. + Current_Subprogram: Iir := Null_Iir; + + function Get_Current_Subprogram return Iir is + begin + return Current_Subprogram; + end Get_Current_Subprogram; + + -- Access to the current concurrent statement. + -- Null_iir if no one. + Current_Concurrent_Statement : Iir := Null_Iir; + + function Get_Current_Concurrent_Statement return Iir is + begin + return Current_Concurrent_Statement; + end Get_Current_Concurrent_Statement; + + -- LRM 8 Sequential statements. + -- All statements may be labeled. + -- Such labels are implicitly declared at the beginning of the declarative + -- part of the innermost enclosing process statement of subprogram body. + procedure Sem_Sequential_Labels (First_Stmt : Iir) + is + Stmt: Iir; + Label: Name_Id; + begin + Stmt := First_Stmt; + while Stmt /= Null_Iir loop + Label := Get_Label (Stmt); + if Label /= Null_Identifier then + Sem_Scopes.Add_Name (Stmt); + Name_Visible (Stmt); + Xref_Decl (Stmt); + end if; + + -- Some statements have sub-lists of statements. + case Get_Kind (Stmt) is + when Iir_Kind_For_Loop_Statement + | Iir_Kind_While_Loop_Statement => + Sem_Sequential_Labels (Get_Sequential_Statement_Chain (Stmt)); + when Iir_Kind_If_Statement => + declare + Clause : Iir; + begin + Clause := Stmt; + while Clause /= Null_Iir loop + Sem_Sequential_Labels + (Get_Sequential_Statement_Chain (Clause)); + Clause := Get_Else_Clause (Clause); + end loop; + end; + when Iir_Kind_Case_Statement => + declare + El : Iir; + begin + El := Get_Case_Statement_Alternative_Chain (Stmt); + while El /= Null_Iir loop + Sem_Sequential_Labels (Get_Associated_Chain (El)); + El := Get_Chain (El); + end loop; + end; + when others => + null; + end case; + Stmt := Get_Chain (Stmt); + end loop; + end Sem_Sequential_Labels; + + procedure Fill_Array_From_Aggregate_Associated + (Chain : Iir; Nbr : in out Natural; Arr : in out Iir_Array) + is + El : Iir; + Ass : Iir; + begin + El := Chain; + while El /= Null_Iir loop + Ass := Get_Associated_Expr (El); + if Get_Kind (Ass) = Iir_Kind_Aggregate then + Fill_Array_From_Aggregate_Associated + (Get_Association_Choices_Chain (Ass), Nbr, Arr); + else + Arr (Nbr) := Ass; + Nbr := Nbr + 1; + end if; + El := Get_Chain (El); + end loop; + end Fill_Array_From_Aggregate_Associated; + + -- Return TRUE iff there is no common elements designed by N1 and N2. + -- N1 and N2 are static names. + -- FIXME: The current implementation is completly wrong; should check from + -- prefix to suffix. + function Is_Disjoint (N1, N2: Iir) return Boolean + is + List1, List2 : Iir_Flist; + El1, El2 : Iir; + begin + if N1 = N2 then + return False; + end if; + if Get_Kind (N1) = Iir_Kind_Indexed_Name + and then Get_Kind (N2) = Iir_Kind_Indexed_Name + then + if Is_Disjoint (Get_Prefix (N1), Get_Prefix (N2)) then + return True; + end if; + -- Check indexes. + List1 := Get_Index_List (N1); + List2 := Get_Index_List (N2); + for I in Flist_First .. Flist_Last (List1) loop + El1 := Get_Nth_Element (List1, I); + El2 := Get_Nth_Element (List2, I); + El1 := Eval_Expr (El1); + Set_Nth_Element (List1, I, El1); + El2 := Eval_Expr (El2); + Set_Nth_Element (List2, I, El2); + -- EL are of discrete type. + if Get_Value (El1) /= Get_Value (El2) then + return True; + end if; + end loop; + return False; + elsif Get_Kind (N1) in Iir_Kinds_Denoting_Name + and then Get_Kind (N2) in Iir_Kinds_Denoting_Name + then + return Get_Named_Entity (N1) /= Get_Named_Entity (N2); + else + return True; + end if; + end Is_Disjoint; + + procedure Check_Uniq_Aggregate_Associated + (Aggr : Iir_Aggregate; Nbr : Natural) + is + Chain : constant Iir := Get_Association_Choices_Chain (Aggr); + subtype El_Array_Type is Iir_Array (0 .. Nbr - 1); + Name_Arr, Obj_Arr : El_Array_Type; + Index : Natural; + El : Iir; + begin + -- Fill the array. + Index := 0; + Fill_Array_From_Aggregate_Associated (Chain, Index, Name_Arr); + -- Should be the same. + pragma Assert (Index = Nbr); + + -- Replace name with object. Return now in case of error (not an + -- object or not a static name). + for I in Name_Arr'Range loop + El := Name_To_Object (Name_Arr (I)); + if El = Null_Iir + or else Get_Name_Staticness (El) /= Locally + then + -- Error... + return; + end if; + Obj_Arr (I) := El; + end loop; + + -- Check each element is uniq. + for I in Name_Arr'Range loop + for J in 0 .. I - 1 loop + if not Is_Disjoint (Obj_Arr (I), Obj_Arr (J)) then + Error_Msg_Sem + (+Name_Arr (I), "target is assigned more than once", + Cont => True); + Error_Msg_Sem + (+Name_Arr (J), " (previous assignment is here)"); + return; + end if; + end loop; + end loop; + end Check_Uniq_Aggregate_Associated; + + -- Do checks for the target of an assignment. + procedure Check_Simple_Signal_Target + (Stmt : Iir; Target : Iir; Staticness : Iir_Staticness); + -- STMT is used to localize the error (if any). + procedure Check_Simple_Variable_Target + (Stmt : Iir; Target : Iir; Staticness : Iir_Staticness); + + -- Semantic associed with signal mode. + -- See LRM93 4.3.3 (or LRM08 6.5.2) + type Boolean_Array_Of_Iir_Mode is array (Iir_Mode) of Boolean; + Iir_Mode_Readable : constant Boolean_Array_Of_Iir_Mode := + (Iir_Unknown_Mode => False, + Iir_In_Mode => True, + Iir_Out_Mode => False, + Iir_Inout_Mode => True, + Iir_Buffer_Mode => True, + Iir_Linkage_Mode => False); + Iir_Mode_Writable : constant Boolean_Array_Of_Iir_Mode := + (Iir_Unknown_Mode => False, + Iir_In_Mode => False, + Iir_Out_Mode => True, + Iir_Inout_Mode => True, + Iir_Buffer_Mode => True, + Iir_Linkage_Mode => False); + + -- Return True iff signal interface INTER is readable. + function Is_Interface_Signal_Readable (Inter : Iir) return Boolean + is + pragma Assert (Get_Kind (Inter) = Iir_Kind_Interface_Signal_Declaration); + Mode : constant Iir_Mode := Get_Mode (Inter); + begin + if Mode = Iir_Out_Mode and then Flags.Vhdl_Std >= Vhdl_08 then + -- LRM08 6.5.2 Interface object declarations + -- OUT. The value of the inerface object is allowed [...] and + -- provided it is not a signal parameter, read. + return not Is_Parameter (Inter); + else + return Iir_Mode_Readable (Mode); + end if; + end Is_Interface_Signal_Readable; + + procedure Check_Aggregate_Target + (Stmt : Iir; Target : Iir; Nbr : in out Natural) + is + Choice : Iir; + Ass : Iir; + begin + Choice := Get_Association_Choices_Chain (Target); + while Choice /= Null_Iir loop + case Get_Kind (Choice) is + when Iir_Kind_Choice_By_Range => + -- LRM93 8.4 + -- It is an error if an element association in such an + -- aggregate contains an OTHERS choice or a choice that is + -- a discrete range. + Error_Msg_Sem + (+Choice, "discrete range choice not allowed for target"); + when Iir_Kind_Choice_By_Others => + -- LRM93 8.4 + -- It is an error if an element association in such an + -- aggregate contains an OTHERS choice or a choice that is + -- a discrete range. + Error_Msg_Sem + (+Choice, "others choice not allowed for target"); + when Iir_Kind_Choice_By_Expression + | Iir_Kind_Choice_By_Name + | Iir_Kind_Choice_By_None => + -- LRM93 9.4 + -- Such a target may not only contain locally static signal + -- names [...] + Ass := Get_Associated_Expr (Choice); + if Get_Kind (Ass) = Iir_Kind_Aggregate then + Check_Aggregate_Target (Stmt, Ass, Nbr); + else + if Get_Kind (Stmt) in + Iir_Kinds_Variable_Assignment_Statement + then + Check_Simple_Variable_Target (Stmt, Ass, Locally); + else + Check_Simple_Signal_Target (Stmt, Ass, Locally); + end if; + Nbr := Nbr + 1; + end if; + when others => + Error_Kind ("check_aggregate_target", Choice); + end case; + Choice := Get_Chain (Choice); + end loop; + end Check_Aggregate_Target; + + procedure Check_Simple_Signal_Target + (Stmt : Iir; Target : Iir; Staticness : Iir_Staticness) + is + Target_Object : Iir; + Target_Prefix : Iir; + Guarded_Target : Tri_State_Type; + Targ_Obj_Kind : Iir_Kind; + begin + Target_Object := Name_To_Object (Target); + if Target_Object = Null_Iir then + Error_Msg_Sem (+Target, "target is not a signal name"); + return; + end if; + + Target_Prefix := Get_Object_Prefix (Target_Object); + Targ_Obj_Kind := Get_Kind (Target_Prefix); + case Targ_Obj_Kind is + when Iir_Kind_Interface_Signal_Declaration => + if not Iir_Mode_Writable (Get_Mode (Target_Prefix)) then + Error_Msg_Sem + (+Target, "%n can't be assigned", +Target_Prefix); + else + Sem_Add_Driver (Target_Object, Stmt); + end if; + when Iir_Kind_Signal_Declaration => + Sem_Add_Driver (Target_Object, Stmt); + when Iir_Kind_Guard_Signal_Declaration => + Error_Msg_Sem (+Stmt, "implicit GUARD signal cannot be assigned"); + return; + when others => + Error_Msg_Sem + (+Stmt, "target (%n) is not a signal", +Get_Base_Name (Target)); + return; + end case; + if Get_Name_Staticness (Target_Object) < Staticness then + Error_Msg_Sem (+Stmt, "signal name must be static"); + end if; + + -- LRM93 2.1.1.2 + -- A formal signal parameter is a guarded signal if and only if + -- it is associated with an actual signal that is a guarded + -- signal. + -- GHDL: a formal signal interface of a subprogram has no static + -- kind. This is determined at run-time, according to the actual + -- associated with the formal. + -- GHDL: parent of target cannot be a function. + if Targ_Obj_Kind = Iir_Kind_Interface_Signal_Declaration + and then Is_Parameter (Target_Prefix) + then + Guarded_Target := Unknown; + else + if Get_Guarded_Signal_Flag (Target_Prefix) then + Guarded_Target := True; + else + Guarded_Target := False; + end if; + end if; + + case Get_Guarded_Target_State (Stmt) is + when Unknown => + Set_Guarded_Target_State (Stmt, Guarded_Target); + when True + | False => + if Get_Guarded_Target_State (Stmt) /= Guarded_Target then + -- LRM93 9.5 + -- It is an error if the target of a concurrent signal + -- assignment is neither a guarded target nor an + -- unguarded target. + Error_Msg_Sem (+Target, "guarded and unguarded target"); + end if; + end case; + end Check_Simple_Signal_Target; + + procedure Check_Simple_Variable_Target + (Stmt : Iir; Target : Iir; Staticness : Iir_Staticness) + is + Target_Object : Iir; + Target_Prefix : Iir; + begin + Target_Object := Name_To_Object (Target); + if Target_Object = Null_Iir then + Error_Msg_Sem (+Stmt, "target is not a variable name"); + return; + end if; + Target_Prefix := Get_Object_Prefix (Target_Object); + case Get_Kind (Target_Prefix) is + when Iir_Kind_Interface_Variable_Declaration => + if not Iir_Mode_Writable (Get_Mode (Target_Prefix)) then + Error_Msg_Sem (+Target, "%n cannot be written (bad mode)", + +Target_Prefix); + return; + end if; + when Iir_Kind_Variable_Declaration => + null; + when Iir_Kind_Implicit_Dereference + | Iir_Kind_Dereference => + -- LRM 3.3 + -- An object designated by an access type is always an object of + -- class variable. + null; + when others => + Error_Msg_Sem (+Stmt, "%n is not a variable to be assigned", + +Target_Prefix); + return; + end case; + if Get_Name_Staticness (Target_Object) < Staticness then + Error_Msg_Sem + (+Target, "element of a target aggregate must be a static name"); + end if; + end Check_Simple_Variable_Target; + + procedure Check_Target (Stmt : Iir; Target : Iir) + is + Nbr : Natural; + begin + if Get_Kind (Target) = Iir_Kind_Aggregate then + Nbr := 0; + Check_Aggregate_Target (Stmt, Target, Nbr); + Check_Uniq_Aggregate_Associated (Target, Nbr); + else + case Get_Kind (Stmt) is + when Iir_Kind_Variable_Assignment_Statement + | Iir_Kind_Conditional_Variable_Assignment_Statement => + Check_Simple_Variable_Target (Stmt, Target, None); + when others => + Check_Simple_Signal_Target (Stmt, Target, None); + end case; + end if; + end Check_Target; + + type Resolve_Stages is (Resolve_Stage_1, Resolve_Stage_2); + pragma Unreferenced (Resolve_Stage_2); + + procedure Sem_Signal_Assignment_Target_And_Option + (Stmt: Iir; Sig_Type : in out Iir) + is + -- The target of the assignment. + Target: Iir; + -- The value that will be assigned. + Expr: Iir; + begin + Target := Get_Target (Stmt); + Target := Sem_Expression_Wildcard (Target, Get_Base_Type (Sig_Type)); + + if Target /= Null_Iir then + Set_Target (Stmt, Target); + if Is_Expr_Fully_Analyzed (Target) then + Check_Target (Stmt, Target); + Sig_Type := Get_Type (Target); + Sem_Types.Set_Type_Has_Signal (Sig_Type); + end if; + end if; + + Expr := Get_Reject_Time_Expression (Stmt); + if Expr /= Null_Iir + and then Is_Expr_Not_Analyzed (Expr) + then + Expr := Sem_Expression (Expr, Time_Type_Definition); + if Expr /= Null_Iir then + Check_Read (Expr); + Set_Reject_Time_Expression (Stmt, Expr); + end if; + end if; + end Sem_Signal_Assignment_Target_And_Option; + + -- Analyze a waveform_list WAVEFORM_LIST that is assigned via statement + -- ASSIGN_STMT to a subelement or a slice of a signal SIGNAL_DECL. + procedure Sem_Waveform_Chain (Waveform_Chain : Iir_Waveform_Element; + Waveform_Type : in out Iir) + is + Expr: Iir; + We: Iir_Waveform_Element; + Time, Last_Time : Iir_Int64; + begin + if Get_Kind (Waveform_Chain) = Iir_Kind_Unaffected_Waveform then + -- Unaffected. + return; + end if; + + -- Start with -1 to allow after 0 ns. + Last_Time := -1; + We := Waveform_Chain; + while We /= Null_Iir loop + Expr := Get_We_Value (We); + if Get_Kind (Expr) = Iir_Kind_Null_Literal then + -- GHDL: allowed only if target is guarded; this is checked by + -- sem_check_waveform_list. + null; + else + Expr := Sem_Expression_Wildcard (Expr, Waveform_Type, True); + + if Expr /= Null_Iir then + if Is_Expr_Fully_Analyzed (Expr) then + Check_Read (Expr); + Expr := Eval_Expr_If_Static (Expr); + end if; + Set_We_Value (We, Expr); + + Merge_Wildcard_Type (Expr, Waveform_Type); + else + Expr := Get_We_Value (We); + Expr := Create_Error_Expr (Expr, Waveform_Type); + Set_We_Value (We, Expr); + end if; + end if; + + -- Analyze time expression. + if Get_Time (We) /= Null_Iir then + Expr := Get_Time (We); + if Is_Expr_Not_Analyzed (Expr) then + Expr := Sem_Expression (Expr, Time_Type_Definition); + if Expr /= Null_Iir then + Set_Time (We, Expr); + Check_Read (Expr); + + if Get_Expr_Staticness (Expr) = Locally + or else (Get_Kind (Expr) = Iir_Kind_Physical_Int_Literal + and then Flags.Flag_Time_64) + then + -- LRM 8.4 + -- It is an error if the time expression in a waveform + -- element evaluates to a negative value. + -- + -- LRM 8.4.1 + -- It is an error if the sequence of new transactions is + -- not in ascending order with repect to time. + -- GHDL: this must be checked at run-time, but this is + -- also checked now for static expressions. + if Get_Expr_Staticness (Expr) = Locally then + -- The expression is static, and therefore may be + -- evaluated. + Expr := Eval_Expr (Expr); + Set_Time (We, Expr); + Time := Get_Value (Expr); + else + -- The expression is a physical literal (common case). + -- Extract its value. + Time := Get_Physical_Value (Expr); + end if; + if Time < 0 then + Error_Msg_Sem + (+Expr, "waveform time expression must be >= 0"); + elsif Time <= Last_Time then + Error_Msg_Sem + (+Expr, + "time must be greather than previous transaction"); + else + Last_Time := Time; + end if; + end if; + end if; + end if; + else + if We /= Waveform_Chain then + -- Time expression must be in ascending order. + Error_Msg_Sem (+We, "time expression required here"); + end if; + + -- LRM93 12.6.4 + -- It is an error if the execution of any postponed process + -- causes a delta cycle to occur immediatly after the current + -- simulation cycle. + -- GHDL: try to warn for such an error; note the context may be + -- a procedure body. + if Current_Concurrent_Statement /= Null_Iir then + case Get_Kind (Current_Concurrent_Statement) is + when Iir_Kind_Sensitized_Process_Statement + | Iir_Kind_Process_Statement + | Iir_Kind_Concurrent_Conditional_Signal_Assignment + | Iir_Kind_Concurrent_Selected_Signal_Assignment => + if Get_Postponed_Flag (Current_Concurrent_Statement) then + Warning_Msg_Sem + (Warnid_Delta_Cycle, +We, + "waveform may cause a delta cycle in a " & + "postponed process"); + end if; + when others => + -- Context is a subprogram. + null; + end case; + end if; + + Last_Time := 0; + end if; + + We := Get_Chain (We); + end loop; + end Sem_Waveform_Chain; + + -- Analyze a waveform chain WAVEFORM_CHAIN that is assigned via statement + -- ASSIGN_STMT to a subelement or a slice of a signal SIGNAL_DECL. + procedure Sem_Check_Waveform_Chain + (Assign_Stmt: Iir; Waveform_Chain: Iir_Waveform_Element) + is + We: Iir_Waveform_Element; + Expr : Iir; + Targ_Type : Iir; + begin + if Get_Kind (Waveform_Chain) = Iir_Kind_Unaffected_Waveform then + return; + end if; + + Targ_Type := Get_Type (Get_Target (Assign_Stmt)); + + We := Waveform_Chain; + while We /= Null_Iir loop + Expr := Get_We_Value (We); + if Get_Kind (Expr) = Iir_Kind_Null_Literal then + -- This is a null waveform element. + -- LRM93 8.4.1 + -- It is an error if the target of a signal assignment statement + -- containing a null waveform is not a guarded signal or an + -- aggregate of guarded signals. + if Get_Guarded_Target_State (Assign_Stmt) = False then + Error_Msg_Sem + (+Assign_Stmt, + "null transactions can be assigned only to guarded signals"); + end if; + else + if Is_Valid (Get_Type (Expr)) + and then not Eval_Is_In_Bound (Expr, Targ_Type) + and then Get_Kind (Expr) /= Iir_Kind_Overflow_Literal + then + Warning_Msg_Sem + (Warnid_Runtime_Error, +We, + "value constraints don't match target ones"); + Set_We_Value (We, Build_Overflow (Expr, Targ_Type)); + end if; + end if; + We := Get_Chain (We); + end loop; + end Sem_Check_Waveform_Chain; + + procedure Sem_Guard (Stmt: Iir) + is + Guard: Iir; + Guard_Interpretation : Name_Interpretation_Type; + begin + Guard := Get_Guard (Stmt); + if Guard = Null_Iir then + -- This assignment is not guarded. + + -- LRM93 9.5 + -- It is an error if a concurrent signal assignment is not a guarded + -- assignment, and the target of the concurrent signal assignment + -- is a guarded target. + if Get_Guarded_Target_State (Stmt) = True then + Error_Msg_Sem + (+Stmt, "not a guarded assignment for a guarded target"); + end if; + return; + end if; + if Guard /= Stmt then + -- if set, guard must be equal to stmt here. + raise Internal_Error; + end if; + Guard_Interpretation := Get_Interpretation (Std_Names.Name_Guard); + if not Valid_Interpretation (Guard_Interpretation) then + Error_Msg_Sem (+Stmt, "no guard signals for this guarded assignment"); + return; + end if; + + Guard := Get_Declaration (Guard_Interpretation); + -- LRM93 9.5: + -- The signal GUARD [...] an explicitly declared signal of type + -- BOOLEAN that is visible at the point of the concurrent signal + -- assignment statement + -- FIXME. + case Get_Kind (Guard) is + when Iir_Kind_Signal_Declaration + | Iir_Kind_Interface_Signal_Declaration + | Iir_Kind_Guard_Signal_Declaration => + null; + when others => + Error_Msg_Sem (+Stmt, "visible GUARD object is not a signal", + Cont => True); + Error_Msg_Sem (+Stmt, "GUARD object is %n", +Guard); + return; + end case; + + if Get_Type (Guard) /= Boolean_Type_Definition then + Error_Msg_Sem (+Guard, "GUARD is not of boolean type"); + end if; + Set_Guard (Stmt, Guard); + end Sem_Guard; + + procedure Sem_Signal_Assignment (Stmt: Iir) + is + Cond_Wf : Iir_Conditional_Waveform; + Expr : Iir; + Wf_Chain : Iir_Waveform_Element; + Target_Type : Iir; + Done : Boolean; + begin + Target_Type := Wildcard_Any_Type; + + Done := False; + for S in Resolve_Stages loop + Sem_Signal_Assignment_Target_And_Option (Stmt, Target_Type); + if Is_Defined_Type (Target_Type) then + Done := True; + end if; + + case Get_Kind (Stmt) is + when Iir_Kind_Concurrent_Simple_Signal_Assignment + | Iir_Kind_Simple_Signal_Assignment_Statement => + Wf_Chain := Get_Waveform_Chain (Stmt); + Sem_Waveform_Chain (Wf_Chain, Target_Type); + if Done then + Sem_Check_Waveform_Chain (Stmt, Wf_Chain); + end if; + + when Iir_Kind_Concurrent_Conditional_Signal_Assignment + | Iir_Kind_Conditional_Signal_Assignment_Statement => + Cond_Wf := Get_Conditional_Waveform_Chain (Stmt); + while Cond_Wf /= Null_Iir loop + Wf_Chain := Get_Waveform_Chain (Cond_Wf); + Sem_Waveform_Chain (Wf_Chain, Target_Type); + if Done then + Sem_Check_Waveform_Chain (Stmt, Wf_Chain); + end if; + if S = Resolve_Stage_1 then + -- Must be analyzed only once. + Expr := Get_Condition (Cond_Wf); + if Expr /= Null_Iir then + Expr := Sem_Condition (Expr); + if Expr /= Null_Iir then + Set_Condition (Cond_Wf, Expr); + end if; + end if; + end if; + Cond_Wf := Get_Chain (Cond_Wf); + end loop; + + when Iir_Kind_Concurrent_Selected_Signal_Assignment => + declare + El : Iir; + begin + El := Get_Selected_Waveform_Chain (Stmt); + while El /= Null_Iir loop + Wf_Chain := Get_Associated_Chain (El); + if Is_Valid (Wf_Chain) then + -- The first choice of a list. + Sem_Waveform_Chain (Wf_Chain, Target_Type); + if Done then + Sem_Check_Waveform_Chain (Stmt, Wf_Chain); + end if; + end if; + El := Get_Chain (El); + end loop; + end; + + when others => + raise Internal_Error; + end case; + + exit when Done; + if not Is_Defined_Type (Target_Type) then + Error_Msg_Sem (+Stmt, "cannot resolve type of waveform"); + exit; + end if; + end loop; + + case Get_Kind (Stmt) is + when Iir_Kind_Concurrent_Simple_Signal_Assignment + | Iir_Kind_Concurrent_Conditional_Signal_Assignment => + Sem_Guard (Stmt); + when others => + null; + end case; + end Sem_Signal_Assignment; + + procedure Sem_Conditional_Expression (Cond_Expr : Iir; Atype : in out Iir) + is + El : Iir; + Expr : Iir; + Cond : Iir; + begin + El := Cond_Expr; + while El /= Null_Iir loop + Expr := Get_Expression (El); + Expr := Sem_Expression_Wildcard (Expr, Atype, True); + + if Expr /= Null_Iir then + Set_Expression (El, Expr); + + if Is_Expr_Fully_Analyzed (Expr) then + Check_Read (Expr); + Expr := Eval_Expr_If_Static (Expr); + end if; + + Merge_Wildcard_Type (Expr, Atype); + end if; + + Cond := Get_Condition (El); + exit when Cond = Null_Iir; + + if Is_Expr_Not_Analyzed (Cond) then + Cond := Sem_Condition (Cond); + Set_Condition (El, Cond); + end if; + + El := Get_Chain (El); + end loop; + end Sem_Conditional_Expression; + + procedure Sem_Variable_Assignment (Stmt: Iir) + is + Target : Iir; + Expr : Iir; + Target_Type : Iir; + Stmt_Type : Iir; + Done : Boolean; + begin + -- LRM93 8.5 Variable assignment statement + -- If the target of the variable assignment statement is in the form of + -- an aggregate, then the type of the aggregate must be determinable + -- from the context, excluding the aggregate itself but including the + -- fact that the type of the aggregate must be a composite type. The + -- base type of the expression on the right-hand side must be the + -- same as the base type of the aggregate. + -- + -- GHDL: this means that the type can only be deduced from the + -- expression (and not from the target). + + Target := Get_Target (Stmt); + Stmt_Type := Wildcard_Any_Type; + for S in Resolve_Stages loop + Done := False; + + Target := Sem_Expression_Wildcard (Target, Stmt_Type); + if Target = Null_Iir then + Target_Type := Stmt_Type; + else + Set_Target (Stmt, Target); + if Is_Expr_Fully_Analyzed (Target) then + Check_Target (Stmt, Target); + Done := True; + end if; + Target_Type := Get_Type (Target); + Stmt_Type := Target_Type; + end if; + + case Iir_Kinds_Variable_Assignment_Statement (Get_Kind (Stmt)) is + when Iir_Kind_Variable_Assignment_Statement => + Expr := Get_Expression (Stmt); + Expr := Sem_Expression_Wildcard (Expr, Stmt_Type, True); + if Expr /= Null_Iir then + if Is_Expr_Fully_Analyzed (Expr) then + Check_Read (Expr); + Expr := Eval_Expr_If_Static (Expr); + end if; + Set_Expression (Stmt, Expr); + Merge_Wildcard_Type (Expr, Stmt_Type); + if Done + and then not Eval_Is_In_Bound (Expr, Target_Type) + and then Get_Kind (Expr) /= Iir_Kind_Overflow_Literal + then + Warning_Msg_Sem + (Warnid_Runtime_Error, +Stmt, + "expression constraints don't match target ones"); + Set_Expression (Stmt, Build_Overflow (Expr, Target_Type)); + end if; + end if; + + when Iir_Kind_Conditional_Variable_Assignment_Statement => + Expr := Get_Conditional_Expression (Stmt); + Sem_Conditional_Expression (Expr, Stmt_Type); + end case; + + exit when Done; + if not Is_Defined_Type (Stmt_Type) then + Error_Msg_Sem (+Stmt, "cannot resolve type"); + if Get_Kind (Target) = Iir_Kind_Aggregate then + -- Try to give an advice. + Error_Msg_Sem (+Stmt, "use a qualified expression for the RHS"); + end if; + exit; + end if; + end loop; + end Sem_Variable_Assignment; + + procedure Sem_Return_Statement (Stmt: Iir_Return_Statement) is + Expr: Iir; + begin + if Current_Subprogram = Null_Iir then + Error_Msg_Sem (+Stmt, "return statement not in a subprogram body"); + return; + end if; + Expr := Get_Expression (Stmt); + case Get_Kind (Current_Subprogram) is + when Iir_Kind_Procedure_Declaration => + if Expr /= Null_Iir then + Error_Msg_Sem + (+Stmt, "return in a procedure can't have an expression"); + end if; + return; + when Iir_Kind_Function_Declaration => + if Expr = Null_Iir then + Error_Msg_Sem + (+Stmt, "return in a function must have an expression"); + return; + end if; + when Iir_Kinds_Process_Statement => + Error_Msg_Sem (+Stmt, "return statement not allowed in a process"); + return; + when others => + Error_Kind ("sem_return_statement", Stmt); + end case; + Set_Type (Stmt, Get_Return_Type (Current_Subprogram)); + Expr := Sem_Expression (Expr, Get_Return_Type (Current_Subprogram)); + if Expr /= Null_Iir then + Check_Read (Expr); + Set_Expression (Stmt, Eval_Expr_If_Static (Expr)); + end if; + end Sem_Return_Statement; + + -- Sem for concurrent and sequential assertion statements. + procedure Sem_Report_Statement (Stmt : Iir) + is + Expr : Iir; + begin + Expr := Get_Report_Expression (Stmt); + if Expr /= Null_Iir then + Expr := Sem_Expression (Expr, String_Type_Definition); + Check_Read (Expr); + Expr := Eval_Expr_If_Static (Expr); + Set_Report_Expression (Stmt, Expr); + end if; + + Expr := Get_Severity_Expression (Stmt); + if Expr /= Null_Iir then + Expr := Sem_Expression (Expr, Severity_Level_Type_Definition); + Check_Read (Expr); + Set_Severity_Expression (Stmt, Expr); + end if; + end Sem_Report_Statement; + + procedure Sem_Assertion_Statement (Stmt: Iir) + is + Expr : Iir; + begin + Expr := Get_Assertion_Condition (Stmt); + Expr := Sem_Condition (Expr); + Expr := Eval_Expr_If_Static (Expr); + Set_Assertion_Condition (Stmt, Expr); + + Sem_Report_Statement (Stmt); + end Sem_Assertion_Statement; + + -- Analyze a list of case choice LIST, and check for correct CHOICE type. + procedure Sem_Case_Choices + (Choice : Iir; Chain : in out Iir; Loc : Location_Type) + is + -- Check restrictions on the expression of a One-Dimensional Character + -- Array Type (ODCAT) given by LRM 8.8 + -- Return FALSE in case of violation. + function Check_Odcat_Expression (Expr : Iir) return Boolean + is + Expr_Type : constant Iir := Get_Type (Expr); + begin + -- LRM 8.8 Case Statement + -- If the expression is of a one-dimensional character array type, + -- then the expression must be one of the following: + case Get_Kind (Expr) is + when Iir_Kinds_Object_Declaration + | Iir_Kind_Selected_Element => + -- FIXME: complete the list. + -- * the name of an object whose subtype is locally static. + if Get_Type_Staticness (Expr_Type) /= Locally then + Error_Msg_Sem + (+Choice, "object subtype is not locally static"); + return False; + end if; + when Iir_Kind_Indexed_Name => + -- LRM93 + -- * an indexed name whose prefix is one of the members of + -- this list and whose indexing expressions are locally + -- static expression. + if Flags.Vhdl_Std = Vhdl_87 then + Error_Msg_Sem + (+Expr, "indexed name not allowed here in vhdl87"); + return False; + end if; + if not Check_Odcat_Expression (Get_Prefix (Expr)) then + return False; + end if; + -- GHDL: I don't understand why the indexing expressions + -- must be locally static. So I don't check this in 93c. + if Flags.Vhdl_Std /= Vhdl_93c + and then + (Get_Expr_Staticness + (Get_Nth_Element (Get_Index_List (Expr), 0)) /= Locally) + then + Error_Msg_Sem + (+Expr, "indexing expression must be locally static"); + return False; + end if; + when Iir_Kind_Slice_Name => + -- LRM93 + -- * a slice name whose prefix is one of the members of this + -- list and whose discrete range is a locally static + -- discrete range. + + -- LRM87/INT1991 IR96 + -- then the expression must be either a slice name whose + -- discrete range is locally static, or .. + if False and Flags.Vhdl_Std = Vhdl_87 then + Error_Msg_Sem + (+Expr, "slice not allowed as case expression in vhdl87"); + return False; + end if; + if not Check_Odcat_Expression (Get_Prefix (Expr)) then + return False; + end if; + if Get_Type_Staticness (Expr_Type) /= Locally then + Error_Msg_Sem + (+Expr, "slice discrete range must be locally static"); + return False; + end if; + when Iir_Kind_Function_Call => + -- LRM93 + -- * a function call whose return type mark denotes a + -- locally static subtype. + if Flags.Vhdl_Std = Vhdl_87 then + Error_Msg_Sem + (+Expr, "function call not allowed here in vhdl87"); + return False; + end if; + if Get_Type_Staticness (Expr_Type) /= Locally then + Error_Msg_Sem + (+Expr, "function call type is not locally static"); + end if; + when Iir_Kind_Qualified_Expression + | Iir_Kind_Type_Conversion => + -- * a qualified expression or type conversion whose type mark + -- denotes a locally static subtype. + if Get_Type_Staticness (Expr_Type) /= Locally then + Error_Msg_Sem + (+Expr, "type mark is not a locally static subtype"); + return False; + end if; + when Iir_Kind_Simple_Name + | Iir_Kind_Selected_Name => + return Check_Odcat_Expression (Get_Named_Entity (Expr)); + when others => + Error_Msg_Sem + (+Choice, "bad form of case expression (refer to LRM 8.8)"); + return False; + end case; + return True; + end Check_Odcat_Expression; + + Choice_Type : constant Iir := Get_Type (Choice); + Low, High : Iir; + El_Type : Iir; + begin + -- LRM 8.8 Case Statement + -- The expression must be of a discrete type, or of a one-dimensional + -- array type whose element base type is a character type. + case Get_Kind (Choice_Type) is + when Iir_Kinds_Discrete_Type_Definition => + Sem_Choices_Range + (Chain, Choice_Type, Low, High, Loc, False, True); + when Iir_Kind_Array_Subtype_Definition + | Iir_Kind_Array_Type_Definition => + if not Is_One_Dimensional_Array_Type (Choice_Type) then + Error_Msg_Sem + (+Choice, + "expression must be of a one-dimensional array type"); + return; + end if; + El_Type := Get_Base_Type (Get_Element_Subtype (Choice_Type)); + if Get_Kind (El_Type) /= Iir_Kind_Enumeration_Type_Definition + or else not Get_Is_Character_Type (El_Type) + then + Error_Msg_Sem + (+Choice, + "element type of the expression must be a character type"); + return; + end if; + if Flags.Vhdl_Std >= Vhdl_08 then + -- No specific restrictions in vhdl 2008. + null; + else + if not Check_Odcat_Expression (Choice) then + return; + end if; + end if; + Sem_String_Choices_Range (Chain, Choice); + when others => + Error_Msg_Sem (+Choice, "type of expression must be discrete"); + end case; + end Sem_Case_Choices; + + procedure Sem_Case_Statement (Stmt: Iir_Case_Statement) + is + Expr: Iir; + Chain : Iir; + El: Iir; + begin + Expr := Get_Expression (Stmt); + Chain := Get_Case_Statement_Alternative_Chain (Stmt); + -- FIXME: overload. + Expr := Sem_Case_Expression (Expr); + if Expr /= Null_Iir then + Check_Read (Expr); + Set_Expression (Stmt, Expr); + + Sem_Case_Choices (Expr, Chain, Get_Location (Stmt)); + Set_Case_Statement_Alternative_Chain (Stmt, Chain); + end if; + + El := Chain; + while El /= Null_Iir loop + if not Get_Same_Alternative_Flag (El) then + Sem_Sequential_Statements_Internal (Get_Associated_Chain (El)); + end if; + El := Get_Chain (El); + end loop; + end Sem_Case_Statement; + + -- Sem the sensitivity list LIST. + procedure Sem_Sensitivity_List (List: Iir_List) + is + El: Iir; + It : List_Iterator; + Res: Iir; + Prefix : Iir; + begin + if List = Iir_List_All then + return; + end if; + + It := List_Iterate (List); + while Is_Valid (It) loop + -- El is an iir_identifier. + El := Get_Element (It); + + if Is_Error (El) then + pragma Assert (Flags.Flag_Force_Analysis); + Res := Error_Mark; + else + Sem_Name (El); + + Res := Get_Named_Entity (El); + end if; + + if Res = Error_Mark then + null; + elsif Is_Overload_List (Res) or else not Is_Object_Name (Res) then + Error_Msg_Sem (+El, "a sensitivity element must be a signal name"); + else + Res := Finish_Sem_Name (El); + Prefix := Get_Object_Prefix (Res); + case Get_Kind (Prefix) is + when Iir_Kind_Signal_Declaration + | Iir_Kind_Guard_Signal_Declaration + | Iir_Kinds_Signal_Attribute => + null; + when Iir_Kind_Interface_Signal_Declaration => + if not Is_Interface_Signal_Readable (Prefix) then + Error_Msg_Sem + (+El, + "%n of mode out can't be in a sensivity list", +Res); + end if; + when others => + Error_Msg_Sem (+El, + "%n is neither a signal nor a port", +Res); + end case; + -- LRM 9.2 + -- Only static signal names (see section 6.1) for which reading + -- is permitted may appear in the sensitivity list of a process + -- statement. + + -- LRM 8.1 Wait statement + -- Each signal name in the sensitivity list must be a static + -- signal name, and each name must denote a signal for which + -- reading is permitted. + if Get_Name_Staticness (Res) < Globally then + Error_Msg_Sem + (+El, "sensitivity element %n must be a static name", +Res); + end if; + + Set_Element (It, Res); + end if; + + Next (It); + end loop; + end Sem_Sensitivity_List; + + -- Mark STMT and its parents as suspendable. + procedure Mark_Suspendable (Stmt : Iir) + is + Parent : Iir; + begin + Parent := Get_Parent (Stmt); + loop + case Get_Kind (Parent) is + when Iir_Kind_Function_Body + | Iir_Kind_Sensitized_Process_Statement => + exit; + when Iir_Kind_Process_Statement + | Iir_Kind_Procedure_Body => + Set_Suspend_Flag (Parent, True); + exit; + when Iir_Kind_If_Statement + | Iir_Kind_While_Loop_Statement + | Iir_Kind_For_Loop_Statement + | Iir_Kind_Case_Statement => + Set_Suspend_Flag (Parent, True); + Parent := Get_Parent (Parent); + when others => + Error_Kind ("mark_suspendable", Parent); + end case; + end loop; + end Mark_Suspendable; + + procedure Sem_Wait_Statement (Stmt: Iir_Wait_Statement) + is + Expr: Iir; + Sensitivity_List : Iir_List; + begin + -- Check validity. + case Get_Kind (Current_Subprogram) is + when Iir_Kind_Process_Statement => + null; + when Iir_Kind_Function_Declaration => + -- LRM93 8.2 + -- It is an error if a wait statement appears in a function + -- subprogram [...] + Error_Msg_Sem + (+Stmt, "wait statement not allowed in a function subprogram"); + return; + when Iir_Kind_Procedure_Declaration => + -- LRM93 8.2 + -- [It is an error ...] or in a procedure that has a parent that + -- is a function subprogram. + -- LRM93 8.2 + -- [...] or in a procedure that has a parent that is such a + -- process statement. + -- GHDL: this is checked at the end of analysis or during + -- elaboration. + Set_Wait_State (Current_Subprogram, True); + when Iir_Kind_Sensitized_Process_Statement => + -- LRM93 8.2 + -- Furthermore, it is an error if a wait statement appears in an + -- explicit process statement that includes a sensitivity list, + -- [...] + Error_Msg_Sem + (+Stmt, "wait statement not allowed in a sensitized process"); + return; + when others => + raise Internal_Error; + end case; + + Sensitivity_List := Get_Sensitivity_List (Stmt); + if Sensitivity_List /= Null_Iir_List then + Sem_Sensitivity_List (Sensitivity_List); + end if; + + Expr := Get_Condition_Clause (Stmt); + if Expr /= Null_Iir then + Expr := Sem_Condition (Expr); + Set_Condition_Clause (Stmt, Expr); + end if; + + Expr := Get_Timeout_Clause (Stmt); + if Expr /= Null_Iir then + Expr := Sem_Expression (Expr, Time_Type_Definition); + if Expr /= Null_Iir then + Check_Read (Expr); + Expr := Eval_Expr_If_Static (Expr); + Set_Timeout_Clause (Stmt, Expr); + if Get_Expr_Staticness (Expr) = Locally + and then Get_Value (Expr) < 0 + then + Error_Msg_Sem (+Stmt, "timeout value must be positive"); + end if; + end if; + end if; + + Mark_Suspendable (Stmt); + end Sem_Wait_Statement; + + procedure Sem_Exit_Next_Statement (Stmt : Iir) + is + Cond: Iir; + Loop_Label : Iir; + Loop_Stmt: Iir; + P : Iir; + begin + Cond := Get_Condition (Stmt); + if Cond /= Null_Iir then + Cond := Sem_Condition (Cond); + Set_Condition (Stmt, Cond); + end if; + + Loop_Label := Get_Loop_Label (Stmt); + if Loop_Label /= Null_Iir then + Loop_Label := Sem_Denoting_Name (Loop_Label); + Set_Loop_Label (Stmt, Loop_Label); + Loop_Stmt := Get_Named_Entity (Loop_Label); + case Get_Kind (Loop_Stmt) is + when Iir_Kind_For_Loop_Statement + | Iir_Kind_While_Loop_Statement => + null; + when others => + Error_Class_Match (Loop_Label, "loop statement"); + Loop_Stmt := Null_Iir; + end case; + else + Loop_Stmt := Null_Iir; + end if; + + -- Check the current statement is inside the labeled loop. + P := Stmt; + loop + P := Get_Parent (P); + case Get_Kind (P) is + when Iir_Kind_While_Loop_Statement + | Iir_Kind_For_Loop_Statement => + if Loop_Stmt = Null_Iir or else P = Loop_Stmt then + exit; + end if; + when Iir_Kind_If_Statement + | Iir_Kind_Elsif + | Iir_Kind_Case_Statement => + null; + when others => + -- FIXME: should emit a message for label mismatch. + Error_Msg_Sem (+Stmt, "exit/next must be inside a loop"); + exit; + end case; + end loop; + end Sem_Exit_Next_Statement; + + -- Process is the scope, this is also the process for which drivers can + -- be created. + procedure Sem_Sequential_Statements_Internal (First_Stmt : Iir) + is + Stmt: Iir; + begin + Stmt := First_Stmt; + while Stmt /= Null_Iir loop + case Get_Kind (Stmt) is + when Iir_Kind_Null_Statement => + null; + when Iir_Kind_If_Statement => + declare + Clause: Iir := Stmt; + Cond: Iir; + begin + while Clause /= Null_Iir loop + Cond := Get_Condition (Clause); + if Cond /= Null_Iir then + Cond := Sem_Condition (Cond); + Set_Condition (Clause, Cond); + end if; + Sem_Sequential_Statements_Internal + (Get_Sequential_Statement_Chain (Clause)); + Clause := Get_Else_Clause (Clause); + end loop; + end; + when Iir_Kind_For_Loop_Statement => + declare + Iterator : constant Iir := + Get_Parameter_Specification (Stmt); + begin + -- LRM 10.1 Declarative region + -- 9. A loop statement. + Open_Declarative_Region; + + Set_Is_Within_Flag (Stmt, True); + Sem_Scopes.Add_Name (Iterator); + Sem_Iterator (Iterator, None); + Set_Visible_Flag (Iterator, True); + Sem_Sequential_Statements_Internal + (Get_Sequential_Statement_Chain (Stmt)); + Set_Is_Within_Flag (Stmt, False); + + Close_Declarative_Region; + end; + when Iir_Kind_While_Loop_Statement => + declare + Cond: Iir; + begin + Cond := Get_Condition (Stmt); + if Cond /= Null_Iir then + Cond := Sem_Condition (Cond); + Set_Condition (Stmt, Cond); + end if; + Sem_Sequential_Statements_Internal + (Get_Sequential_Statement_Chain (Stmt)); + end; + when Iir_Kind_Simple_Signal_Assignment_Statement + | Iir_Kind_Conditional_Signal_Assignment_Statement => + Sem_Signal_Assignment (Stmt); + if Current_Concurrent_Statement /= Null_Iir and then + Get_Kind (Current_Concurrent_Statement) + in Iir_Kinds_Process_Statement + and then Get_Passive_Flag (Current_Concurrent_Statement) + then + Error_Msg_Sem + (+Stmt, "signal statement forbidden in passive process"); + end if; + when Iir_Kind_Variable_Assignment_Statement + | Iir_Kind_Conditional_Variable_Assignment_Statement => + Sem_Variable_Assignment (Stmt); + when Iir_Kind_Return_Statement => + Sem_Return_Statement (Stmt); + when Iir_Kind_Assertion_Statement => + Sem_Assertion_Statement (Stmt); + when Iir_Kind_Report_Statement => + Sem_Report_Statement (Stmt); + when Iir_Kind_Case_Statement => + Sem_Case_Statement (Stmt); + when Iir_Kind_Wait_Statement => + Sem_Wait_Statement (Stmt); + when Iir_Kind_Procedure_Call_Statement => + declare + Call : constant Iir := Get_Procedure_Call (Stmt); + Imp : Iir; + begin + Sem_Procedure_Call (Call, Stmt); + + -- Set suspend flag, if calling a suspendable procedure + -- from a procedure or from a process. + Imp := Get_Implementation (Call); + if Imp /= Null_Iir + and then Get_Kind (Imp) = Iir_Kind_Procedure_Declaration + and then Get_Suspend_Flag (Imp) + and then (Get_Kind (Get_Current_Subprogram) + /= Iir_Kind_Function_Declaration) + and then (Get_Kind (Get_Current_Subprogram) + /= Iir_Kind_Sensitized_Process_Statement) + then + Set_Suspend_Flag (Stmt, True); + Mark_Suspendable (Stmt); + end if; + end; + when Iir_Kind_Next_Statement + | Iir_Kind_Exit_Statement => + Sem_Exit_Next_Statement (Stmt); + when others => + Error_Kind ("sem_sequential_statements_Internal", Stmt); + end case; + Stmt := Get_Chain (Stmt); + end loop; + end Sem_Sequential_Statements_Internal; + + procedure Sem_Sequential_Statements (Decl : Iir; Body_Parent : Iir) + is + Outer_Subprogram: Iir; + begin + Outer_Subprogram := Current_Subprogram; + Current_Subprogram := Decl; + + -- Sem declarations + Sem_Sequential_Labels (Get_Sequential_Statement_Chain (Body_Parent)); + Sem_Declaration_Chain (Body_Parent); + Sem_Specification_Chain (Body_Parent, Null_Iir); + + -- Sem statements. + Sem_Sequential_Statements_Internal + (Get_Sequential_Statement_Chain (Body_Parent)); + + Check_Full_Declaration (Body_Parent, Body_Parent); + + Current_Subprogram := Outer_Subprogram; + end Sem_Sequential_Statements; + + -- Sem the instantiated unit of STMT and return the node constaining + -- ports and generics (either a entity_declaration or a component + -- declaration). + function Sem_Instantiated_Unit + (Stmt : Iir_Component_Instantiation_Statement) return Iir + is + Inst : constant Iir := Get_Instantiated_Unit (Stmt); + Comp_Name : Iir; + Comp : Iir; + begin + if Get_Kind (Inst) in Iir_Kinds_Entity_Aspect then + return Sem_Entity_Aspect (Inst); + else + Comp := Get_Named_Entity (Inst); + if Comp /= Null_Iir then + -- Already analyzed before, while trying to separate + -- concurrent procedure calls from instantiation stmts. + pragma Assert (Get_Kind (Comp) = Iir_Kind_Component_Declaration); + return Comp; + end if; + + -- Needs a denoting name + if Get_Kind (Inst) not in Iir_Kinds_Denoting_Name then + Error_Msg_Sem (+Inst, "name for a component expected"); + return Null_Iir; + end if; + + -- The component may be an entity or a configuration. + Comp_Name := Sem_Denoting_Name (Inst); + Set_Instantiated_Unit (Stmt, Comp_Name); + Comp := Get_Named_Entity (Comp_Name); + if Get_Kind (Comp) /= Iir_Kind_Component_Declaration then + Error_Class_Match (Comp_Name, "component"); + return Null_Iir; + end if; + + return Comp; + end if; + end Sem_Instantiated_Unit; + + procedure Sem_Component_Instantiation_Statement + (Stmt: Iir_Component_Instantiation_Statement; Is_Passive : Boolean) + is + Decl : Iir; + Entity_Unit : Iir_Design_Unit; + Bind : Iir_Binding_Indication; + begin + -- FIXME: move this check in parse ? + if Is_Passive then + Error_Msg_Sem (+Stmt, "component instantiation forbidden in entity"); + end if; + + -- Check for label. + -- This cannot be moved in parse since a procedure_call may be revert + -- into a component instantiation. + if Get_Label (Stmt) = Null_Identifier then + Error_Msg_Sem (+Stmt, "component instantiation requires a label"); + end if; + + -- Look for the component. + Decl := Sem_Instantiated_Unit (Stmt); + if Decl = Null_Iir then + return; + end if; + + -- The association + Sem_Generic_Port_Association_Chain (Decl, Stmt); + + -- FIXME: add sources for signals, in order to detect multiple sources + -- to unresolved signals. + -- What happen if the component is not bound ? + + -- Create a default binding indication if necessary. + if Get_Component_Configuration (Stmt) = Null_Iir + and then Is_Component_Instantiation (Stmt) + then + Entity_Unit := Get_Visible_Entity_Declaration (Decl); + if Entity_Unit = Null_Iir then + if Is_Warning_Enabled (Warnid_Default_Binding) + and then not Flags.Flag_Elaborate + then + Warning_Msg_Sem + (Warnid_Default_Binding, +Stmt, + "no default binding for instantiation of %n", +Decl); + Explain_No_Visible_Entity (Decl); + end if; + elsif Flags.Flag_Elaborate + and then (Flags.Flag_Elaborate_With_Outdated + or else Get_Date (Entity_Unit) in Date_Valid) + then + Bind := Sem_Create_Default_Binding_Indication + (Decl, Entity_Unit, Stmt, False, True); + Set_Default_Binding_Indication (Stmt, Bind); + end if; + end if; + end Sem_Component_Instantiation_Statement; + + -- Note: a statement such as + -- label1: name; + -- can be parsed as a procedure call statement or as a + -- component instantiation statement. + -- Check now and revert in case of error. + function Sem_Concurrent_Procedure_Call_Statement + (Stmt : Iir; Is_Passive : Boolean) return Iir + is + Call : Iir_Procedure_Call; + Decl : Iir; + Label : Name_Id; + N_Stmt : Iir_Component_Instantiation_Statement; + Imp : Iir; + begin + Call := Get_Procedure_Call (Stmt); + if Get_Parameter_Association_Chain (Call) = Null_Iir then + Imp := Get_Prefix (Call); + Sem_Name (Imp); + Set_Prefix (Call, Imp); + + Decl := Get_Named_Entity (Imp); + if Get_Kind (Decl) = Iir_Kind_Component_Declaration then + N_Stmt := Create_Iir (Iir_Kind_Component_Instantiation_Statement); + Label := Get_Label (Stmt); + Set_Label (N_Stmt, Label); + Set_Parent (N_Stmt, Get_Parent (Stmt)); + Set_Instantiated_Unit (N_Stmt, Finish_Sem_Name (Imp)); + Location_Copy (N_Stmt, Stmt); + + if Label /= Null_Identifier then + -- A component instantiation statement must have + -- a label, this condition is checked during the + -- sem of the statement. + Sem_Scopes.Replace_Name (Label, Stmt, N_Stmt); + end if; + + Free_Iir (Stmt); + Free_Iir (Call); + + Sem_Component_Instantiation_Statement (N_Stmt, Is_Passive); + return N_Stmt; + end if; + end if; + Sem_Procedure_Call (Call, Stmt); + + if Is_Passive then + Imp := Get_Implementation (Call); + if Imp /= Null_Iir + and then Get_Kind (Imp) = Iir_Kind_Procedure_Declaration + then + Decl := Get_Interface_Declaration_Chain (Imp); + while Decl /= Null_Iir loop + if Get_Mode (Decl) in Iir_Out_Modes then + Error_Msg_Sem (+Stmt, "%n is not passive", +Imp); + exit; + end if; + Decl := Get_Chain (Decl); + end loop; + end if; + end if; + + return Stmt; + end Sem_Concurrent_Procedure_Call_Statement; + + procedure Sem_Block_Statement (Stmt: Iir_Block_Statement) + is + Header : constant Iir_Block_Header := Get_Block_Header (Stmt); + Guard : constant Iir_Guard_Signal_Declaration := Get_Guard_Decl (Stmt); + Expr: Iir; + Generic_Chain : Iir; + Port_Chain : Iir; + begin + -- LRM 10.1 Declarative region. + -- 7. A block statement. + Open_Declarative_Region; + + Set_Is_Within_Flag (Stmt, True); + + if Header /= Null_Iir then + Generic_Chain := Get_Generic_Chain (Header); + Sem_Interface_Chain (Generic_Chain, Generic_Interface_List); + Port_Chain := Get_Port_Chain (Header); + Sem_Interface_Chain (Port_Chain, Port_Interface_List); + + -- LRM 9.1 + -- Such actuals are evaluated in the context of the enclosing + -- declarative region. + -- GHDL: close the declarative region... + Set_Is_Within_Flag (Stmt, False); + Close_Declarative_Region; + + Sem_Generic_Port_Association_Chain (Header, Header); + + -- ... and reopen-it. + Open_Declarative_Region; + Set_Is_Within_Flag (Stmt, True); + Add_Declarations_From_Interface_Chain (Generic_Chain); + Add_Declarations_From_Interface_Chain (Port_Chain); + end if; + + -- LRM93 9.1 + -- If a guard expression appears after the reserved word BLOCK, then a + -- signal with the simple name GUARD of predefined type BOOLEAN is + -- implicitly declared at the beginning of the declarative part of the + -- block, and the guard expression defined the value of that signal at + -- any given time. + if Guard /= Null_Iir then + -- LRM93 9.1 + -- The type of the guard expression must be type BOOLEAN. + -- GHDL: guard expression must be analyzed before creating the + -- implicit GUARD signal, since the expression may reference GUARD. + Set_Expr_Staticness (Guard, None); + Set_Name_Staticness (Guard, Locally); + Expr := Get_Guard_Expression (Guard); + Expr := Sem_Condition (Expr); + if Expr /= Null_Iir then + Set_Guard_Expression (Guard, Expr); + end if; + + -- FIXME: should extract sensivity now and set the has_active flag + -- on signals, since the guard expression is evaluated when one of + -- its signal is active. However, how can a bug be introduced by + -- evaluating only when signals have events ? + + -- the guard expression is an implicit definition of a signal named + -- GUARD. Create this definition. This is necessary for the type. + Set_Identifier (Guard, Std_Names.Name_Guard); + Set_Type (Guard, Boolean_Type_Definition); + Set_Block_Statement (Guard, Stmt); + Sem_Scopes.Add_Name (Guard); + Set_Visible_Flag (Guard, True); + end if; + + Sem_Block (Stmt); + Set_Is_Within_Flag (Stmt, False); + Close_Declarative_Region; + end Sem_Block_Statement; + + procedure Sem_Generate_Statement_Body (Bod : Iir) is + begin + Set_Is_Within_Flag (Bod, True); + Sem_Block (Bod); + Set_Is_Within_Flag (Bod, False); + end Sem_Generate_Statement_Body; + + procedure Sem_For_Generate_Statement (Stmt : Iir) + is + Param : constant Iir := Get_Parameter_Specification (Stmt); + begin + -- LRM93 10.1 Declarative region. + -- 12. A generate statement. + Open_Declarative_Region; + Set_Is_Within_Flag (Stmt, True); + + Sem_Scopes.Add_Name (Param); + + -- LRM93 7.4.2 (Globally Static Primaries) + -- 4. a generate parameter; + Sem_Iterator (Param, Globally); + Set_Visible_Flag (Param, True); + + -- LRM93 9.7 + -- The discrete range in a generation scheme of the first form must + -- be a static discrete range; + if Get_Type (Param) /= Null_Iir + and then Get_Type_Staticness (Get_Type (Param)) < Globally + then + Error_Msg_Sem (+Stmt, "range must be a static discrete range"); + end if; + + -- In the same declarative region. + Sem_Generate_Statement_Body (Get_Generate_Statement_Body (Stmt)); + + Set_Is_Within_Flag (Stmt, True); + Close_Declarative_Region; + end Sem_For_Generate_Statement; + + procedure Sem_If_Case_Generate_Statement_Body (Bod : Iir) + is + Alt_Label : Name_Id; + begin + Alt_Label := Get_Alternative_Label (Bod); + if Alt_Label /= Null_Identifier then + -- Declare label. This doesn't appear in the LRM (bug ?), but + -- used here to detect duplicated labels. + Sem_Scopes.Add_Name (Bod); + Xref_Decl (Bod); + end if; + + -- Contrary to the LRM, a new declarative region is declared. This + -- is required so that declarations in a generate statement body are + -- not in the scope of the following generate bodies. + Open_Declarative_Region; + Sem_Generate_Statement_Body (Bod); + Close_Declarative_Region; + end Sem_If_Case_Generate_Statement_Body; + + procedure Sem_If_Generate_Statement (Stmt : Iir) + is + Clause : Iir; + Condition : Iir; + begin + -- LRM93 10.1 Declarative region. + -- 12. A generate statement. + Open_Declarative_Region; + Set_Is_Within_Flag (Stmt, True); + + Clause := Stmt; + while Clause /= Null_Iir loop + Condition := Get_Condition (Clause); + + if Condition /= Null_Iir then + Condition := Sem_Condition (Condition); + -- LRM93 9.7 + -- the condition in a generation scheme of the second form must be + -- a static expression. + if Condition /= Null_Iir + and then Get_Expr_Staticness (Condition) < Globally + then + Error_Msg_Sem + (+Condition, "condition must be a static expression"); + else + Set_Condition (Clause, Condition); + end if; + else + -- No condition for the last 'else' part. + pragma Assert (Get_Generate_Else_Clause (Clause) = Null_Iir); + null; + end if; + + Sem_If_Case_Generate_Statement_Body + (Get_Generate_Statement_Body (Clause)); + + Clause := Get_Generate_Else_Clause (Clause); + end loop; + + Set_Is_Within_Flag (Stmt, False); + Close_Declarative_Region; + end Sem_If_Generate_Statement; + + procedure Sem_Case_Generate_Statement (Stmt : Iir) + is + Expr : Iir; + Chain : Iir; + El : Iir; + begin + -- LRM93 10.1 Declarative region. + -- 12. A generate statement. + Open_Declarative_Region; + Set_Is_Within_Flag (Stmt, True); + + Expr := Get_Expression (Stmt); + Chain := Get_Case_Statement_Alternative_Chain (Stmt); + -- FIXME: overload. + Expr := Sem_Case_Expression (Expr); + if Expr /= Null_Iir then + Check_Read (Expr); + Set_Expression (Stmt, Expr); + + if Get_Expr_Staticness (Expr) < Globally then + Error_Msg_Sem + (+Expr, "case expression must be a static expression"); + end if; + + Sem_Case_Choices (Expr, Chain, Get_Location (Stmt)); + Set_Case_Statement_Alternative_Chain (Stmt, Chain); + end if; + + El := Chain; + while El /= Null_Iir loop + if not Get_Same_Alternative_Flag (El) then + Sem_If_Case_Generate_Statement_Body (Get_Associated_Block (El)); + end if; + El := Get_Chain (El); + end loop; + + Set_Is_Within_Flag (Stmt, False); + Close_Declarative_Region; + end Sem_Case_Generate_Statement; + + procedure Sem_Process_Statement (Proc: Iir) is + begin + Set_Is_Within_Flag (Proc, True); + + -- LRM 10.1 + -- 8. A process statement + Open_Declarative_Region; + + -- Sem declarations + Sem_Sequential_Statements (Proc, Proc); + + Close_Declarative_Region; + + Set_Is_Within_Flag (Proc, False); + + if Get_Kind (Proc) = Iir_Kind_Sensitized_Process_Statement + and then Get_Callees_List (Proc) /= Null_Iir_List + then + -- Check there is no wait statement in subprograms called. + -- Also in the case of all-sensitized process, check that package + -- subprograms don't read signals. + Sem.Add_Analysis_Checks_List (Proc); + end if; + end Sem_Process_Statement; + + procedure Sem_Sensitized_Process_Statement + (Proc: Iir_Sensitized_Process_Statement) is + begin + Sem_Sensitivity_List (Get_Sensitivity_List (Proc)); + Sem_Process_Statement (Proc); + end Sem_Sensitized_Process_Statement; + + procedure Sem_Concurrent_Selected_Signal_Assignment (Stmt: Iir) + is + Expr: Iir; + Chain : Iir; + begin + -- LRM 9.5 Concurrent Signal Assgnment Statements. + -- The process statement equivalent to a concurrent signal assignment + -- statement [...] is constructed as follows: [...] + -- + -- LRM 9.5.2 Selected Signal Assignment + -- The characteristics of the selected expression, the waveforms and + -- the choices in the selected assignment statement must be such that + -- the case statement in the equivalent statement is a legal + -- statement + + -- Target and waveforms. + Sem_Signal_Assignment (Stmt); + + -- The choices. + Chain := Get_Selected_Waveform_Chain (Stmt); + Expr := Sem_Case_Expression (Get_Expression (Stmt)); + if Expr /= Null_Iir then + Check_Read (Expr); + Set_Expression (Stmt, Expr); + Sem_Case_Choices (Expr, Chain, Get_Location (Stmt)); + Set_Selected_Waveform_Chain (Stmt, Chain); + end if; + + Sem_Guard (Stmt); + end Sem_Concurrent_Selected_Signal_Assignment; + + procedure Simple_Simultaneous_Statement (Stmt : Iir) is + Left, Right : Iir; + Res_Type : Iir; + begin + Left := Get_Simultaneous_Left (Stmt); + Right := Get_Simultaneous_Right (Stmt); + + Left := Sem_Expression_Ov (Left, Null_Iir); + Right := Sem_Expression_Ov (Right, Null_Iir); + + -- Give up in case of error + if Left = Null_Iir or else Right = Null_Iir then + return; + end if; + + Res_Type := Search_Compatible_Type (Get_Type (Left), Get_Type (Right)); + if Res_Type = Null_Iir then + Error_Msg_Sem + (+Stmt, "types of left and right expressions are incompatible"); + return; + end if; + + -- FIXME: check for nature type... + end Simple_Simultaneous_Statement; + + procedure Sem_Concurrent_Statement_Chain (Parent : Iir) + is + Is_Passive : constant Boolean := + Get_Kind (Parent) = Iir_Kind_Entity_Declaration; + El: Iir; + New_El : Iir; + Next_El : Iir; + + procedure No_Generate_Statement is + begin + if Is_Passive then + Error_Msg_Sem (+El, "generate statement forbidden in entity"); + end if; + end No_Generate_Statement; + + Prev_El : Iir; + Prev_Concurrent_Statement : Iir; + begin + Prev_Concurrent_Statement := Current_Concurrent_Statement; + + El := Get_Concurrent_Statement_Chain (Parent); + Prev_El := Null_Iir; + while El /= Null_Iir loop + Current_Concurrent_Statement := El; + New_El := El; + Next_El := Get_Chain (El); + + case Get_Kind (El) is + when Iir_Kind_Concurrent_Simple_Signal_Assignment + | Iir_Kind_Concurrent_Conditional_Signal_Assignment => + if Is_Passive then + Error_Msg_Sem (+El, "signal assignment forbidden in entity"); + end if; + Sem_Signal_Assignment (El); + when Iir_Kind_Concurrent_Selected_Signal_Assignment => + if Is_Passive then + Error_Msg_Sem (+El, "signal assignment forbidden in entity"); + end if; + Sem_Concurrent_Selected_Signal_Assignment (El); + when Iir_Kind_Sensitized_Process_Statement => + Set_Passive_Flag (El, Is_Passive); + Sem_Sensitized_Process_Statement (El); + when Iir_Kind_Process_Statement => + Set_Passive_Flag (El, Is_Passive); + Sem_Process_Statement (El); + when Iir_Kind_Component_Instantiation_Statement => + Sem_Component_Instantiation_Statement (El, Is_Passive); + when Iir_Kind_Concurrent_Assertion_Statement => + -- FIXME: must check assertion expressions does not contain + -- non-passive subprograms ?? + Sem_Assertion_Statement (El); + when Iir_Kind_Block_Statement => + if Is_Passive then + Error_Msg_Sem (+El, "block forbidden in entity"); + end if; + Sem_Block_Statement (El); + when Iir_Kind_If_Generate_Statement => + No_Generate_Statement; + Sem_If_Generate_Statement (El); + when Iir_Kind_For_Generate_Statement => + No_Generate_Statement; + Sem_For_Generate_Statement (El); + when Iir_Kind_Case_Generate_Statement => + No_Generate_Statement; + Sem_Case_Generate_Statement (El); + when Iir_Kind_Concurrent_Procedure_Call_Statement => + New_El := Sem_Concurrent_Procedure_Call_Statement + (El, Is_Passive); + when Iir_Kind_Psl_Declaration => + Sem_Psl.Sem_Psl_Declaration (El); + when Iir_Kind_Psl_Endpoint_Declaration => + Sem_Psl.Sem_Psl_Endpoint_Declaration (El); + when Iir_Kind_Psl_Assert_Statement => + New_El := Sem_Psl.Sem_Psl_Assert_Statement (El); + when Iir_Kind_Psl_Cover_Statement => + Sem_Psl.Sem_Psl_Cover_Statement (El); + when Iir_Kind_Psl_Default_Clock => + Sem_Psl.Sem_Psl_Default_Clock (El); + when Iir_Kind_Simple_Simultaneous_Statement => + Simple_Simultaneous_Statement (El); + when others => + Error_Kind ("sem_concurrent_statement_chain", El); + end case; + + if New_El /= El then + -- Replace this node. + if Prev_El = Null_Iir then + Set_Concurrent_Statement_Chain (Parent, New_El); + else + Set_Chain (Prev_El, New_El); + end if; + Set_Chain (New_El, Next_El); + Set_Parent (New_El, Parent); + Prev_El := New_El; + else + Prev_El := El; + pragma Assert (Get_Parent (El) = Parent); + end if; + + El := Next_El; + end loop; + + Current_Concurrent_Statement := Prev_Concurrent_Statement; + end Sem_Concurrent_Statement_Chain; + + -- Put labels in declarative region. + procedure Sem_Labels_Chain (Parent : Iir) + is + Stmt: Iir; + Label: Name_Id; + begin + Stmt := Get_Concurrent_Statement_Chain (Parent); + while Stmt /= Null_Iir loop + + case Get_Kind (Stmt) is + when Iir_Kind_Psl_Declaration + | Iir_Kind_Psl_Endpoint_Declaration => + -- Special case for in-lined PSL declarations. + null; + when others => + Label := Get_Label (Stmt); + + if Label /= Null_Identifier then + Sem_Scopes.Add_Name (Stmt); + Name_Visible (Stmt); + Xref_Decl (Stmt); + end if; + end case; + + -- INT-1991/issue report 27 + -- Generate statements represent declarative region and have + -- implicit declarative part. + if False + and then Flags.Vhdl_Std = Vhdl_87 + and then + (Get_Kind (Stmt) = Iir_Kind_For_Generate_Statement + or else Get_Kind (Stmt) = Iir_Kind_If_Generate_Statement) + then + Sem_Labels_Chain (Stmt); + end if; + + Stmt := Get_Chain (Stmt); + end loop; + end Sem_Labels_Chain; + + procedure Sem_Block (Blk: Iir) + is + Implicit : Implicit_Signal_Declaration_Type; + Prev_Psl_Default_Clock : Iir; + begin + Prev_Psl_Default_Clock := Current_Psl_Default_Clock; + Push_Signals_Declarative_Part (Implicit, Blk); + + Sem_Labels_Chain (Blk); + Sem_Declaration_Chain (Blk); + + Sem_Concurrent_Statement_Chain (Blk); + + -- FIXME: do it only if there is conf. spec. in the declarative + -- part. + Sem_Specification_Chain (Blk, Blk); + Check_Full_Declaration (Blk, Blk); + + Pop_Signals_Declarative_Part (Implicit); + Current_Psl_Default_Clock := Prev_Psl_Default_Clock; + end Sem_Block; + + -- Add a driver for SIG. + -- STMT is used in case of error (it is the statement that creates the + -- driver). + -- Do nothing if: + -- The current statement list does not belong to a process, + -- SIG is a formal signal interface. + procedure Sem_Add_Driver (Sig : Iir; Stmt : Iir) + is + Sig_Object : Iir; + Sig_Object_Type : Iir; + begin + if Sig = Null_Iir then + return; + end if; + Sig_Object := Get_Object_Prefix (Sig); + Sig_Object_Type := Get_Type (Sig_Object); + + -- LRM 4.3.1.2 Signal Declaration + -- It is an error if, after the elaboration of a description, a + -- signal has multiple sources and it is not a resolved signal. + + -- Check for multiple driver for a unresolved signal declaration. + -- Do this only if the object is a non-composite signal declaration. + -- NOTE: THIS IS DISABLED, since the assignment may be within a + -- generate statement. + if False + and then Get_Kind (Sig_Object) = Iir_Kind_Signal_Declaration + and then Get_Kind (Sig_Object_Type) + not in Iir_Kinds_Composite_Type_Definition + and then not Get_Resolved_Flag (Sig_Object_Type) + then + if Get_Signal_Driver (Sig_Object) /= Null_Iir and then + Get_Signal_Driver (Sig_Object) /= Current_Concurrent_Statement + then + Error_Msg_Sem (+Stmt, "unresolved %n has already a driver at %l", + (+Sig_Object, +Get_Signal_Driver (Sig_Object))); + else + Set_Signal_Driver (Sig_Object, Current_Concurrent_Statement); + end if; + end if; + + -- LRM 8.4.1 + -- If a given procedure is declared by a declarative item that is not + -- contained within a process statement, and if a signal assignment + -- statement appears in that procedure, then the target of the + -- assignment statement must be a formal parameter of the given + -- procedure or of a parent of that procedure, or an aggregate of such + -- formal parameters. + -- Similarly, if a given procedure is declared by a declarative item + -- that is not contained within a process statement and if a signal is + -- associated with an INOUT or OUT mode signal parameter in a + -- subprogram call within that procedure, then the signal so associated + -- must be a formal parameter of the given procedure or of a parent of + -- that procedure. + if Current_Concurrent_Statement = Null_Iir + or else (Get_Kind (Current_Concurrent_Statement) + not in Iir_Kinds_Process_Statement) + then + -- Not within a process statement. + if Current_Subprogram = Null_Iir then + -- not within a subprogram: concurrent statement. + return; + end if; + + -- Within a subprogram. + if Get_Kind (Sig_Object) = Iir_Kind_Signal_Declaration + or else not Is_Parameter (Sig_Object) + then + Error_Msg_Sem (+Stmt, "%n is not a formal parameter", +Sig_Object); + end if; + end if; + end Sem_Add_Driver; +end Vhdl.Sem_Stmts; |