def valid_path_to_next_field_condition( message: model.Message, field: model.Field, prefix: str ) -> Sequence[Expr]: return [ If( [ ( l.condition.substituted(substitution(message, public=True, prefix=prefix)) .simplified() .ada_expr(), And( Equal( Call( "Predecessor", [Variable("Ctx"), Variable(l.target.affixed_name)], ), Variable(field.affixed_name), ), Call( "Valid_Next", [Variable("Ctx"), Variable(l.target.affixed_name)], ) if l.target != model.FINAL else TRUE, ), ) ] ) for l in message.outgoing(field) if l.target != model.FINAL ]
def field_condition_call( prefix: str, message: model.Message, field: model.Field, value: Expr = None, aggregate: Expr = None, size: Expr = None, ) -> Expr: package = prefix * message.identifier if value is None: value = Number(0) if aggregate is None: aggregate = EMPTY_ARRAY if size is None: size = Call( package * "Field_Size", [Variable("Ctx"), Variable(package * field.affixed_name)], ) return Call( package * "Field_Condition", [ Variable("Ctx"), Variable(package * field.affixed_name), *([value] if has_value_dependent_condition(message) else []), *([aggregate] if has_aggregate_dependent_condition(message) else []), *([size] if has_size_dependent_condition(message, field) else []), ], )
def set_context_cursor_composite_field(field_name: str) -> Assignment: return Assignment( Indexed( Variable("Ctx.Cursors"), Variable(field_name), ), NamedAggregate( ("State", Variable("S_Structural_Valid")), ( "First", Call( "Field_First", [Variable("Ctx"), Variable(field_name)], ), ), ( "Last", Call( "Field_Last", [Variable("Ctx"), Variable(field_name)], ), ), ("Value", Variable("Value")), ( "Predecessor", Selected( Indexed( Variable("Ctx.Cursors"), Variable(field_name), ), "Predecessor", ), ), ), )
def public_context_predicate() -> Expr: return And( GreaterEqual(Call(const.TYPES_TO_INDEX, [Variable("First")]), Variable("Buffer_First")), LessEqual(Call(const.TYPES_TO_INDEX, [Variable("Last")]), Variable("Buffer_Last")), Less(Variable("Buffer_Last"), Last(const.TYPES_INDEX)), LessEqual(Variable("First"), Add(Variable("Last"), Number(1))), Less(Variable("Last"), Last(const.TYPES_BIT_INDEX)), Equal(Rem(Variable("First"), Size(const.TYPES_BYTE)), Number(1)), Equal(Rem(Variable("Last"), Size(const.TYPES_BYTE)), Number(0)), )
def create_valid_function() -> UnitPart: specification = FunctionSpecification( "Valid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")]) return UnitPart( [ SubprogramDeclaration( specification, [ Postcondition( If([( Result("Valid"), And( Call( "Structural_Valid", [Variable("Ctx"), Variable("Fld")], ), Call("Present", [Variable("Ctx"), Variable("Fld")]), ), )])), ], ) ], private=[ ExpressionFunctionDeclaration( specification, AndThen( Equal( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "State"), Variable("S_Valid"), ), Less( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "First"), Add( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "Last"), Number(1), ), ), ), ) ], )
def context_cursor_unchanged( message: model.Message, field: model.Field, predecessors: bool ) -> List[Expr]: lower: model.Field upper: model.Field if predecessors: if len(message.predecessors(field)) == 0: return [] lower = message.fields[0] upper = message.fields[message.fields.index(field) - 1] else: if len(message.successors(field)) == 0: return [] lower = message.fields[message.fields.index(field) + 1] upper = message.fields[-1] return [ ForAllIn( "F", ValueRange( lower=Variable(lower.affixed_name), upper=Variable(upper.affixed_name), type_identifier=ID("Field"), ), Equal( Call( "Context_Cursors_Index", [ Call( "Context_Cursors", [Variable("Ctx")], ), Variable("F"), ], ), Call( "Context_Cursors_Index", [ Old( Call( "Context_Cursors", [Variable("Ctx")], ) ), Variable("F"), ], ), ), ) ]
def field_bit_location_declarations(field_name: Name) -> Sequence[Declaration]: return [ ObjectDeclaration( ["First"], const.TYPES_BIT_INDEX, Call("Field_First", [Variable("Ctx"), field_name]), constant=True, ), ObjectDeclaration( ["Last"], const.TYPES_BIT_INDEX, Call("Field_Last", [Variable("Ctx"), field_name]), constant=True, ), ]
def create_verify_message_procedure(self, message: Message) -> UnitPart: specification = ProcedureSpecification( "Verify_Message", [InOutParameter(["Ctx"], "Context")]) loop_invariant = And( Call("Has_Buffer", [Variable("Ctx")]), *common.context_invariant(message, loop_entry=True), ) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], )), Postcondition( And( Call("Has_Buffer", [Variable("Ctx")]), *common.context_invariant(message), )), ], ) ], [ SubprogramBody( specification, [], [ ForIn( "F", Variable("Field"), [ PragmaStatement("Loop_Invariant", [loop_invariant]), CallStatement("Verify", [Variable("Ctx"), Variable("F")]), ], ) ], ) ], )
def create_valid_message_function(self, message: Message) -> UnitPart: specification = FunctionSpecification("Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [ Precondition( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], )) ], ) ], private=[ ExpressionFunctionDeclaration( specification, self.valid_message_condition(message), ) ], )
def _create_init_proc(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: proc = ProcedureSpecification( "Initialize", [OutParameter(["S"], "Slots"), Parameter(["M"], "Memory")]) return UnitPart( [ SubprogramDeclaration( proc, [Postcondition(Call("Initialized", [Variable("S")]))]), ], [ SubprogramBody( proc, declarations=[], statements=([ Assignment( "S" * self._slot_name(slot.slot_id), UnrestrictedAccess( Variable(ID(f"M.Slot_{slot.slot_id}"))), ) for slot in slots ] if slots else [NullStatement()]), aspects=[SparkMode(off=True)], ) ], )
def set_context_cursor_scalar() -> Assignment: return Assignment( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), NamedAggregate( ("State", Variable("S_Valid")), ("First", Call("Field_First", [Variable("Ctx"), Variable("Fld")])), ("Last", Call("Field_Last", [Variable("Ctx"), Variable("Fld")])), ("Value", Variable("Value")), ( "Predecessor", Selected(Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "Predecessor"), ), ), )
def cursors_invariant() -> Expr: return ForAllIn( "F", Variable("Field"), If( [ ( Call( "Structural_Valid", [Indexed(Variable("Cursors"), Variable("F"))], ), And( GreaterEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Variable("First"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"), Variable("Verified_Last"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Add( Selected( Indexed(Variable("Cursors"), Variable("F")), "Last", ), Number(1), ), ), Call( "Valid_Value", [ Variable("F"), Selected( Indexed(Variable("Cursors"), Variable("F")), "Value", ), ], ), ), ) ] ), )
def result(field: Field) -> Expr: return Call( "To_Actual", [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), "Value") ], )
def create_scalar_getter_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar]) -> UnitPart: def specification(field: Field, field_type: Type) -> FunctionSpecification: if field_type.package == BUILTINS_PACKAGE: type_identifier = ID(field_type.name) else: type_identifier = self.prefix * field_type.identifier return FunctionSpecification(f"Get_{field.name}", type_identifier, [Parameter(["Ctx"], "Context")]) def result(field: Field) -> Expr: return Call( "To_Actual", [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), "Value") ], ) return UnitPart( [ # https://github.com/Componolit/Workarounds/issues/31 Pragma( "Warnings", [Variable("Off"), String("precondition is always False")]), *[ SubprogramDeclaration( specification(f, t), [ Precondition( Call( self.prefix * message.identifier * "Valid", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), ) ], ) for f, t in scalar_fields.items() ], Pragma( "Warnings", [Variable("On"), String("precondition is always False")]), ], private=[ ExpressionFunctionDeclaration(specification(f, t), result(f)) for f, t in scalar_fields.items() ], )
def valid_predecessors_invariant() -> Expr: return AndThen( *[ If( [ ( Call( "Structural_Valid", [ Indexed( Variable("Cursors"), Variable(f.affixed_name), ) ], ), Or( *[ expr.AndThen( expr.Call( "Structural_Valid" if l.source in composite_fields else "Valid", [ expr.Indexed( expr.Variable("Cursors"), expr.Variable(l.source.affixed_name), ) ], ), expr.Equal( expr.Selected( expr.Indexed( expr.Variable("Cursors"), expr.Variable(f.affixed_name), ), "Predecessor", ), expr.Variable(l.source.affixed_name), ), l.condition.substituted( substitution(message, embedded=True, prefix=prefix) ), ) .simplified() .ada_expr() for l in message.incoming(f) ] ), ) ] ) for f in message.fields if f not in message.direct_successors(model.INITIAL) ] )
def initialize_conditions(message: model.Message) -> Sequence[Expr]: return [ *[ Equal( Variable("Ctx" * ID(p.name)), Variable(p.name), ) for p, t in message.parameter_types.items() ], Call("Initialized", [Variable("Ctx")]), ]
def byte_aligned_field(prefix: str, message: model.Message, field: model.Field) -> Expr: return Equal( Rem( Call( prefix * message.identifier * "Field_First", [ Variable("Ctx"), Variable(prefix * message.identifier * field.affixed_name), ], ), Size(const.TYPES_BYTE), ), Number(1), )
def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call( "Invalid", [ Indexed( Variable("Cursors"), Variable(p.affixed_name), ) ], ) for p in message.direct_predecessors(f) ] ), Call( "Invalid", [ Indexed( Variable("Cursors"), Variable(f.affixed_name), ) ], ), ) ] ) for f in message.fields if f not in message.direct_successors(model.INITIAL) ] )
def create_incomplete_message_function() -> UnitPart: specification = FunctionSpecification("Incomplete_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [ # https://github.com/Componolit/Workarounds/issues/47 Pragma( "Warnings", [ Variable("Off"), String( "postcondition does not mention function result") ], ), SubprogramDeclaration(specification, [Postcondition(TRUE)]), Pragma( "Warnings", [ Variable("On"), String( "postcondition does not mention function result") ], ), ], private=[ ExpressionFunctionDeclaration( specification, ForSomeIn( "F", Variable("Field"), Call( "Incomplete", [Variable("Ctx"), Variable("F")], ), ), ) ], )
def unchanged_cursor_before_or_invalid( limit: Expr, loop_entry: bool, or_invalid: bool = True ) -> Expr: return ForAllIn( "F", Variable("Field"), IfExpr( [ ( Less(Variable("F"), limit), Equal( Indexed( Variable("Ctx.Cursors"), Variable("F"), ), Indexed( LoopEntry(Variable("Ctx.Cursors")) if loop_entry else Old(Variable("Ctx.Cursors")), Variable("F"), ), ), ) ], *( [ Call( "Invalid", [ Variable("Ctx"), Variable("F"), ], ) ] if or_invalid else [] ), ), )
def _create_finalize_proc(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: proc = ProcedureSpecification("Finalize", [InOutParameter(["S"], "Slots")]) return UnitPart( [ SubprogramDeclaration( proc, [Postcondition(Call("Uninitialized", [Variable("S")]))]), ], [ SubprogramBody( proc, declarations=[], statements=([ Assignment( "S" * self._slot_name(slot.slot_id), Variable("null"), ) for slot in slots ] if slots else [NullStatement()]), aspects=[SparkMode(off=True)], ) ], )
def create_generic_opaque_getter_procedures( self, message: Message, opaque_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Generic_Get_{field.name}", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( And( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], ), Call( self.prefix * message.identifier * "Present", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), )) ], [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{f.name}", [Parameter([f.name], const.TYPES_BYTES)])) ], ) for f in opaque_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "First", ) ], ), constant=True, ), ObjectDeclaration( ["Last"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "Last", ) ], ), constant=True, ), ], [ CallStatement( f"Process_{f.name}", [ Slice(Variable("Ctx.Buffer.all"), Variable("First"), Variable("Last")) ], ) ], ) for f in opaque_fields ], )
def create_opaque_getter_procedures( self, message: Message, opaque_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Get_{field.name}", [ Parameter(["Ctx"], "Context"), OutParameter(["Data"], const.TYPES_BYTES) ], ) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( AndThen( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], ), Call( self.prefix * message.identifier * "Structural_Valid", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), Call( self.prefix * message.identifier * "Valid_Next", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), Equal( Length("Data"), Call( const.TYPES_TO_LENGTH, [ Call( self.prefix * message.identifier * "Field_Size", [ Variable("Ctx"), Variable(self.prefix * message.identifier * f.affixed_name), ], ) ], ), ), )), Postcondition( Call( "Equal", [ Variable("Ctx"), Variable(f.affixed_name), Variable("Data"), ], )), ], ) for f in opaque_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "First", ) ], ), constant=True, ), ObjectDeclaration( ["Last"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "Last", ) ], ), constant=True, ), ], [ Assignment( "Data", NamedAggregate( ("others", First(const.TYPES_BYTE))), ), Assignment( Slice( Variable("Data"), First("Data"), Add(First("Data"), Sub(Variable("Last"), Variable("First"))), ), Slice( Variable("Ctx.Buffer.all"), Variable("First"), Variable("Last"), ), ), ], ) for f in opaque_fields ], )
def message_structure_invariant( message: model.Message, prefix: str, link: model.Link = None, embedded: bool = False ) -> Expr: def prefixed(name: str) -> expr.Expr: return expr.Selected(expr.Variable("Ctx"), name) if not embedded else expr.Variable(name) if not link: return message_structure_invariant( message, prefix, message.outgoing(model.INITIAL)[0], embedded ) source = link.source target = link.target if target == model.FINAL: return TRUE field_type = message.types[target] condition = link.condition.substituted(substitution(message, prefix, embedded)).simplified() size = ( field_type.size if isinstance(field_type, model.Scalar) else link.size.substituted( substitution(message, prefix, embedded, target_type=const.TYPES_BIT_LENGTH) ).simplified() ) first = ( prefixed("First") if source == model.INITIAL else link.first.substituted( substitution(message, prefix, embedded, target_type=const.TYPES_BIT_INDEX) ) .substituted( mapping={ expr.UNDEFINED: expr.Add( expr.Selected( expr.Indexed(prefixed("Cursors"), expr.Variable(source.affixed_name)), "Last", ), expr.Number(1), ) } ) .simplified() ) invariant = [ message_structure_invariant(message, prefix, l, embedded) for l in message.outgoing(target) ] return If( [ ( AndThen( Call( "Structural_Valid", [Indexed(prefixed("Cursors").ada_expr(), Variable(target.affixed_name))], ), *([condition.ada_expr()] if condition != expr.TRUE else []), ), AndThen( Equal( Add( Sub( Selected( Indexed( prefixed("Cursors").ada_expr(), Variable(target.affixed_name), ), "Last", ), Selected( Indexed( prefixed("Cursors").ada_expr(), Variable(target.affixed_name), ), "First", ), ), Number(1), ), size.ada_expr(), ), Equal( Selected( Indexed( prefixed("Cursors").ada_expr(), Variable(target.affixed_name), ), "Predecessor", ), Variable(source.affixed_name), ), Equal( Selected( Indexed( prefixed("Cursors").ada_expr(), Variable(target.affixed_name), ), "First", ), first.ada_expr(), ), *[i for i in invariant if i != TRUE], ), ) ] )
def create_opaque_getter_functions( self, message: Message, opaque_fields: Sequence[Field]) -> UnitPart: def name(field: Field) -> str: return f"Get_{field.name}" def specification(field: Field) -> FunctionSpecification: return FunctionSpecification( name(field), const.TYPES_BYTES, [Parameter(["Ctx"], "Context")], ) return UnitPart( [ SubprogramDeclaration( specification(f), [ Ghost(), Precondition( AndThen( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], ), Call( self.prefix * message.identifier * "Structural_Valid", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), Call( self.prefix * message.identifier * "Valid_Next", [ Variable("Ctx"), Variable( self.prefix * message.identifier * f.affixed_name), ], ), )), Postcondition( Equal( Length(Result(name(f))), Call( const.TYPES_TO_LENGTH, [ Call( "Field_Size", [ Variable("Ctx"), Variable(f.affixed_name), ], ) ], ), )), ], ) for f in opaque_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "First", ) ], ), constant=True, ), ObjectDeclaration( ["Last"], const.TYPES_INDEX, Call( const.TYPES_TO_INDEX, [ Selected( Indexed( Variable("Ctx.Cursors"), Variable(f.affixed_name), ), "Last", ) ], ), constant=True, ), ], [ ReturnStatement( Slice(Variable("Ctx.Buffer.all"), Variable("First"), Variable("Last")), ) ], ) for f in opaque_fields ], )
def sufficient_space_for_field_condition( message_id: ID, field_name: Name, size: Expr = None ) -> Expr: if size is None: size = Call(message_id * "Field_Size", [Variable("Ctx"), field_name]) return GreaterEqual(Call(message_id * "Available_Space", [Variable("Ctx"), field_name]), size)
def initialize_field_statements( field: model.Field, reset_written_last: bool = False ) -> Sequence[Statement]: return [ CallStatement( "Reset_Dependent_Fields", [Variable("Ctx"), Variable(field.affixed_name)], ), # https://github.com/Componolit/RecordFlux/issues/868 PragmaStatement( "Warnings", [ Variable("Off"), String("attribute Update is an obsolescent feature"), ], ), Assignment( "Ctx", Update( "Ctx", ("Verified_Last", Variable("Last")), ( "Written_Last", Variable("Last") if reset_written_last else Max( const.TYPES_BIT_LENGTH, Variable("Ctx.Written_Last"), Variable("Last"), ), ), ), ), PragmaStatement( "Warnings", [ Variable("On"), String("attribute Update is an obsolescent feature"), ], ), Assignment( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), NamedAggregate( ("State", Variable("S_Structural_Valid")), ("First", Variable("First")), ("Last", Variable("Last")), ("Value", Number(0)), ( "Predecessor", Selected( Indexed( Variable("Ctx.Cursors"), Variable(field.affixed_name), ), "Predecessor", ), ), ), ), Assignment( Indexed( Variable("Ctx.Cursors"), Call( "Successor", [Variable("Ctx"), Variable(field.affixed_name)], ), ), NamedAggregate( ("State", Variable("S_Invalid")), ("Predecessor", Variable(field.affixed_name)), ), ), ]
def create_verify_procedure( self, message: Message, scalar_fields: Mapping[Field, Scalar], composite_fields: Sequence[Field], ) -> UnitPart: specification = ProcedureSpecification( "Verify", [InOutParameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")]) valid_field_condition = AndThen( Call( "Valid_Value", [Variable("Fld"), Variable("Value")], ), Call( "Field_Condition", [ Variable("Ctx"), Variable("Fld"), *([Variable("Value")] if common.has_value_dependent_condition(message) else []), *([ Slice( Variable("Ctx.Buffer.all"), Call( const.TYPES_TO_INDEX, [ Call("Field_First", [Variable("Ctx"), Variable("Fld")]) ], ), Call( const.TYPES_TO_INDEX, [ Call("Field_Last", [Variable("Ctx"), Variable("Fld")]) ], ), ) ] if common.has_aggregate_dependent_condition(message) else []), *([Call("Field_Size", [Variable("Ctx"), Variable("Fld")])] if common.has_size_dependent_condition(message) else []), ], ), ) last = Mul( Div( Add( Call("Field_Last", [Variable("Ctx"), Variable("Fld")]), Size(const.TYPES_BYTE), -Number(1), ), Size(const.TYPES_BYTE), ), Size(const.TYPES_BYTE), ) set_cursors_statements = [ *([ PragmaStatement( "Assert", [ If([( Or(*[ Equal(Variable("Fld"), Variable( f.affixed_name)) for f in message.direct_predecessors(FINAL) ]), Equal( Mod( Call("Field_Last", [Variable("Ctx"), Variable("Fld")]), Size(const.TYPES_BYTE), ), Number(0), ), )]) ], ) ] if len(message.fields) > 1 else []), # Improve provability of context predicate PragmaStatement( "Assert", [Equal(Mod(last, Size(const.TYPES_BYTE)), Number(0))]), Assignment(Variable("Ctx.Verified_Last"), last), PragmaStatement( "Assert", [ LessEqual( Call("Field_Last", [Variable("Ctx"), Variable("Fld")]), Variable("Ctx.Verified_Last"), ) ], ), IfStatement( [( Call("Composite_Field", [Variable("Fld")]), [set_context_cursor_composite_field("Fld")], )], [set_context_cursor_scalar()], ) if scalar_fields and composite_fields else set_context_cursor_scalar() if scalar_fields and not composite_fields else set_context_cursor_composite_field("Fld"), *([ # https://github.com/Componolit/RecordFlux/issues/664 # The provability of the context predicate is increased by splitting the # assignment into multiple statements. Assignment( Indexed( Variable("Ctx.Cursors"), Call( "Successor", [Variable("Ctx"), Variable("Fld")], ), ), NamedAggregate( ("State", Variable("S_Invalid")), ("Predecessor", Variable("Fld")), ), ) ] if len(message.fields) > 1 else []), ] return UnitPart( [ SubprogramDeclaration( specification, [ Precondition( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], )), Postcondition( And( Call("Has_Buffer", [Variable("Ctx")]), *common.context_invariant(message), )), ], ) ], [ SubprogramBody( specification, [ObjectDeclaration(["Value"], const.TYPES_BASE_INT)], [ IfStatement([( AndThen( Call( "Invalid", [ Indexed(Variable("Ctx.Cursors"), Variable("Fld")) ], ), Call("Valid_Predecessor", [Variable("Ctx"), Variable("Fld")]), Call("Path_Condition", [Variable("Ctx"), Variable("Fld")]), ), [ IfStatement( [( Call( "Sufficient_Buffer_Length", [Variable("Ctx"), Variable("Fld")], ), [ Assignment( "Value", If( [( Call( "Composite_Field", [ Variable( "Fld"), ], ), Number(0), )], Call( "Get", [ Variable("Ctx"), Variable("Fld"), ], ), ) if scalar_fields and composite_fields else Call( "Get", [ Variable("Ctx"), Variable("Fld"), ], ) if scalar_fields else Number(0), ), IfStatement( [( valid_field_condition, set_cursors_statements, )], [ Assignment( Indexed( Variable( "Ctx.Cursors"), Variable("Fld"), ), NamedAggregate( ( "State", Variable( "S_Invalid" ), ), ( "Predecessor", Variable( FINAL. affixed_name, ), ), ), ) ], ), ], )], [ Assignment( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), NamedAggregate( ("State", Variable("S_Incomplete")), ( "Predecessor", Variable( FINAL.affixed_name), ), ), ) ], ) ], )], ) ], ) ], )
def create_get_function( self, message: Message, scalar_fields: Mapping[Field, Scalar], composite_fields: Sequence[Field], ) -> UnitPart: if not scalar_fields: return UnitPart() comparison_to_aggregate = any( (isinstance(t, Composite) and common.has_aggregate_dependent_condition(message, f)) for f, t in message.field_types.items()) big_endian_fields = [ f for f in scalar_fields if message.byte_order[f] == ByteOrder.HIGH_ORDER_FIRST ] little_endian_fields = [ f for f in scalar_fields if message.byte_order[f] == ByteOrder.LOW_ORDER_FIRST ] return UnitPart( [], [ SubprogramBody( FunctionSpecification( "Get", const.TYPES_BASE_INT, [ Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field") ], ), [ *common.field_bit_location_declarations( Variable("Fld")), ObjectDeclaration( ["Buffer_First"], const.TYPES_INDEX, Call(const.TYPES_TO_INDEX, [Variable("First")]), constant=True, ), ObjectDeclaration( ["Buffer_Last"], const.TYPES_INDEX, Call(const.TYPES_TO_INDEX, [Variable("Last")]), constant=True, ), ObjectDeclaration( ["Offset"], const.TYPES_OFFSET, Call( const.TYPES_OFFSET, [ Mod( Sub( Size(const.TYPES_BYTE), Mod(Variable("Last"), Size(const.TYPES_BYTE)), ), Size(const.TYPES_BYTE), ) ], ), constant=True, ), ObjectDeclaration( ["Size"], "Positive", Case( Variable("Fld"), [ *[(Variable(f.affixed_name), t.size.ada_expr()) for f, t in scalar_fields.items()], *([(Variable("others"), Last("Positive"))] if composite_fields else []), ], ), constant=True, ), ObjectDeclaration( ["Byte_Order"], const.TYPES_BYTE_ORDER, If( [( In( Variable("Fld"), ChoiceList(*[ Variable(f.affixed_name) for f in big_endian_fields ]), ), Variable(const.TYPES_HIGH_ORDER_FIRST), )], Variable(const.TYPES_LOW_ORDER_FIRST), ) if big_endian_fields and little_endian_fields else Variable(const.TYPES_HIGH_ORDER_FIRST) if big_endian_fields else Variable( const.TYPES_LOW_ORDER_FIRST), constant=True, ), ] if scalar_fields or comparison_to_aggregate else [], [ ReturnStatement( Call( const.TYPES * "Extract", [ Variable("Ctx.Buffer"), Variable("Buffer_First"), Variable("Buffer_Last"), Variable("Offset"), Variable("Size"), Variable("Byte_Order"), ], ), ), ], [ Precondition( AndThen( Call( self.prefix * message.identifier * "Has_Buffer", [Variable("Ctx")], ), Call( self.prefix * message.identifier * "Valid_Next", [Variable("Ctx"), Variable("Fld")], ), Call( self.prefix * message.identifier * "Sufficient_Buffer_Length", [Variable("Ctx"), Variable("Fld")], ), *([ Not( Call( self.prefix * message.identifier * "Composite_Field", [Variable("Fld")], )) ] if composite_fields else []), )), ], ), ], )