def create_present_function() -> UnitPart: specification = FunctionSpecification( "Present", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")]) return UnitPart( [SubprogramDeclaration(specification)], [ ExpressionFunctionDeclaration( specification, AndThen( Call("Structural_Valid", [ Indexed(Variable("Ctx.Cursors"), Variable("Fld")) ]), Less( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "First"), Add( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "Last"), Number(1), ), ), ), ) ], )
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_invalid_function() -> UnitPart: specification = FunctionSpecification( "Invalid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")]) return UnitPart( [SubprogramDeclaration(specification)], [ ExpressionFunctionDeclaration( specification, Or( Equal( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "State"), Variable("S_Invalid"), ), Equal( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "State"), Variable("S_Incomplete"), ), ), ) ], )
def create_structural_valid_function() -> UnitPart: specification = FunctionSpecification( "Structural_Valid", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ) return UnitPart( [SubprogramDeclaration(specification)], [ ExpressionFunctionDeclaration( specification, And( Or(*[ Equal( Selected( Indexed(Variable("Ctx.Cursors"), Variable("Fld")), "State"), Variable(s), ) for s in ("S_Valid", "S_Structural_Valid") ])), ) ], )
def field_byte_location_declarations() -> Sequence[Declaration]: return [ ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("Last")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Offset", const.TYPES_OFFSET), Call( const.TYPES_OFFSET, [Mod(Sub(Number(8), Mod(Variable("Last"), Number(8))), Number(8))], ), ), ]
def specification(field: Field, field_type: Type) -> FunctionSpecification: if field_type.package == BUILTINS_PACKAGE: type_name = ID(field_type.name) else: type_name = self.prefix * field_type.identifier return FunctionSpecification(f"Get_{field.name}", type_name, [Parameter(["Ctx"], "Context")])
def field_byte_location_declarations(self) -> Sequence[Declaration]: return [ ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", self.types.index), Call(self.types.byte_index, [Name("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", self.types.index), Call(self.types.byte_index, [Name("Last")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Offset", self.types.offset), Call( self.types.offset, [Mod(Sub(Number(8), Mod(Name("Last"), Number(8))), Number(8))], ), ), ]
def extract_function(self, type_name: str) -> Subprogram: return GenericFunctionInstantiation( "Extract", FunctionSpecification( f"{self.types.types}.Extract", type_name, [Parameter(["Buffer"], self.types.bytes), Parameter(["Offset"], self.types.offset)], ), [self.types.index, self.types.byte, self.types.bytes, self.types.offset, type_name], )
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")]), ), )])), ], ) ], [ 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 _create_init_pred(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: return UnitPart([ ExpressionFunctionDeclaration( FunctionSpecification("Initialized", "Boolean", [Parameter(["S"], "Slots")]), And(*[ NotEqual( Variable("S" * self._slot_name(slot.slot_id)), Variable("null"), ) for slot in slots ]), ) ])
def extract_function(self, type_name: ID) -> Subprogram: return GenericFunctionInstantiation( "Extract", FunctionSpecification( const.TYPES * "Extract", type_name, [ Parameter(["Buffer"], const.TYPES_BYTES), Parameter(["Offset"], const.TYPES_OFFSET), ], ), [common.prefixed_type_name(type_name, self.prefix)], )
def create_valid_message_function(self, message: Message) -> UnitPart: specification = FunctionSpecification( "Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")] ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, valid_message_condition(message).simplified(self.common.substitution(message)), ) ], )
def formal_parameters( field: Field) -> Sequence[FormalSubprogramDeclaration]: return [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{field.name}", [OutParameter([field.name], const.TYPES_BYTES)], )), FormalSubprogramDeclaration( FunctionSpecification( "Valid_Length", "Boolean", [Parameter(["Length"], const.TYPES_LENGTH)], )), ]
def create_incomplete_function() -> UnitPart: specification = FunctionSpecification( "Incomplete", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")] ) return UnitPart( [SubprogramDeclaration(specification, [Precondition(VALID_CONTEXT)])], [ ExpressionFunctionDeclaration( specification, Equal( Selected(Indexed("Ctx.Cursors", Name("Fld")), "State"), Name("S_Incomplete") ), ) ], )
def create_incomplete_message_function(message: Message) -> UnitPart: specification = FunctionSpecification("Incomplete_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [SubprogramDeclaration(specification)], [ ExpressionFunctionDeclaration( specification, Or(*[ Call("Incomplete", [Variable("Ctx"), Variable(f.affixed_name)]) for f in message.fields ]), ) ], )
def create_valid_message_function(message: Message) -> UnitPart: specification = FunctionSpecification("Valid_Message", "Boolean", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [Precondition(Call("Has_Buffer", [Variable("Ctx")]))], ) ], [ ExpressionFunctionDeclaration( specification, valid_message_condition(message).substituted( common.substitution(message)).simplified(), ) ], )
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 _create_global_allocated_pred( self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: return UnitPart([ ExpressionFunctionDeclaration( FunctionSpecification("Global_Allocated", "Boolean", [Parameter(["S"], "Slots")]), And( *[ Equal( Variable("S" * self._slot_name(slot.slot_id)), Variable("null"), ) for slot in slots if slot.global_ ], *[ NotEqual( Variable("S" * self._slot_name(slot.slot_id)), Variable("null"), ) for slot in slots if not slot.global_ ], ), ) ])
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 []), )), ], ), ], )
def create_composite_setter_procedures(self, message: Message) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Set_{field.name}", [InOutParameter(["Ctx"], "Context")]) def specification_bounded(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Set_Bounded_{field.name}", [InOutParameter(["Ctx"], "Context"), Parameter(["Length"], self.types.bit_length)], ) formal_parameters = [ FormalSubprogramDeclaration( ProcedureSpecification( "Process_Payload", [OutParameter(["Payload"], self.types.bytes)], ) ) ] return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.unbounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], formal_parameters, ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramDeclaration( specification_bounded(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.bounded_composite_setter_preconditions(message, f), ) ), Postcondition( And( *self.composite_setter_postconditions(message, f, message.types[f]), ) ), ], formal_parameters, ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], [ SubprogramBody( specification(f), [ *self.common.field_bit_location_declarations(Name(f.affixed_name)), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", self.types.index), Call(self.types.byte_index, [Name("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", self.types.index), Call(self.types.byte_index, [Name("Last")]), ), ], [ CallStatement(f"Initialize_{f.name}", [Name("Ctx")]), CallStatement( "Process_Payload", [ Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and unbounded_setter_required(message, f) ] + [ SubprogramBody( specification_bounded(f), [ ObjectDeclaration( ["First"], self.types.bit_index, Call("Field_First", [Name("Ctx"), Name(f.affixed_name)]), True, ), ObjectDeclaration( ["Last"], self.types.bit_index, Add(Name("First"), Name("Length"), -Number(1)), True, ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", self.types.index), Call(self.types.byte_index, [Name("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", self.types.index), Call(self.types.byte_index, [Name("Last")]), ), ], [ CallStatement( f"Initialize_Bounded_{f.name}", [Name("Ctx"), Name("Length")] ), CallStatement( "Process_Payload", [ Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], )
def specification(field: Field) -> FunctionSpecification: return FunctionSpecification( name(field), const.TYPES_BYTES, [Parameter(["Ctx"], "Context")], )
def create_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Type], composite_fields: Sequence[Field], ) -> UnitPart: def result(field: Field, message: Message) -> NamedAggregate: aggregate: List[Tuple[str, Expr]] = [ ("Fld", Variable(field.affixed_name)) ] if field in message.fields and isinstance(message.types[field], Scalar): aggregate.append(( f"{field.name}_Value", Call( "Extract", [ Slice( Variable("Ctx.Buffer.all"), Variable("Buffer_First"), Variable("Buffer_Last"), ), Variable("Offset"), ], ), )) return NamedAggregate(*aggregate) return UnitPart( [], [ ExpressionFunctionDeclaration( FunctionSpecification("Composite_Field", "Boolean", [Parameter(["Fld"], "Field")]), Case( Variable("Fld"), [(Variable(f.affixed_name), TRUE if f in composite_fields else FALSE) for f in message.fields], ), ), SubprogramBody( FunctionSpecification( "Get_Field_Value", "Field_Dependent_Value", [ Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field") ], ), [ *common.field_bit_location_declarations( Variable("Fld")), *common.field_byte_location_declarations(), *unique( self.extract_function(common.full_base_type_name( t)) for t in message.types.values() if isinstance(t, Scalar)), ] if scalar_fields else [], [ ReturnStatement( Case( Variable("Fld"), [(Variable(f.affixed_name), result(f, message)) for f in message.fields], )) ], [ Precondition( AndThen( Call("Has_Buffer", [Variable("Ctx")]), Call("Valid_Next", [Variable("Ctx"), Variable("Fld")]), Call("Sufficient_Buffer_Length", [Variable("Ctx"), Variable("Fld")]), )), Postcondition( Equal( Selected(Result("Get_Field_Value"), "Fld"), Variable("Fld"), )), ], ), ], )
def create_composite_setter_procedures(self, message: Message) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Set_{field.name}", [InOutParameter(["Ctx"], "Context")]) def specification_bounded(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Set_Bounded_{field.name}", [ InOutParameter(["Ctx"], "Context"), Parameter(["Length"], const.TYPES_BIT_LENGTH) ], ) def formal_parameters( field: Field) -> Sequence[FormalSubprogramDeclaration]: return [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{field.name}", [OutParameter([field.name], const.TYPES_BYTES)], )), FormalSubprogramDeclaration( FunctionSpecification( "Valid_Length", "Boolean", [Parameter(["Length"], const.TYPES_LENGTH)], )), ] return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.unbounded_composite_setter_preconditions( message, f), Call( "Valid_Length", [ Call( const.TYPES_LENGTH, [ Div( Call( "Field_Length", [ Variable("Ctx"), Variable( f.affixed_name) ], ), Size(const.TYPES_BYTE), ), ], ), ], ), )), Postcondition( And( *self.composite_setter_postconditions( message, f), )), ], formal_parameters(f), ) for f, t in message.types.items() if isinstance(t, Opaque) and unbounded_setter_required(message, f) ] + [ SubprogramDeclaration( specification_bounded(f), [ Precondition( AndThen( *self.setter_preconditions(f), *self.bounded_composite_setter_preconditions( message, f), Call( "Valid_Length", [ Call( const.TYPES_LENGTH, [ Div(Variable("Length"), Size(const.TYPES_BYTE)) ], ) ], ), )), Postcondition( And( *self.composite_setter_postconditions( message, f), )), ], formal_parameters(f), ) for f, t in message.types.items() if isinstance(t, Opaque) and bounded_setter_required(message, f) ], [ SubprogramBody( specification(f), [ *common.field_bit_location_declarations( Variable(f.affixed_name)), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("Last")]), ), ], [ CallStatement(f"Initialize_{f.name}", [Variable("Ctx")]), CallStatement( f"Process_{f.name}", [ Slice( Selected(Variable("Ctx.Buffer"), "all"), Variable("Buffer_First"), Variable("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Opaque) and unbounded_setter_required(message, f) ] + [ SubprogramBody( specification_bounded(f), [ ObjectDeclaration( ["First"], const.TYPES_BIT_INDEX, Call("Field_First", [Variable("Ctx"), Variable(f.affixed_name)]), True, ), ObjectDeclaration( ["Last"], const.TYPES_BIT_INDEX, Add(Variable("First"), Variable("Length"), -Number(1)), True, ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_First", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("First")]), ), ExpressionFunctionDeclaration( FunctionSpecification("Buffer_Last", const.TYPES_INDEX), Call(const.TYPES_BYTE_INDEX, [Variable("Last")]), ), ], [ CallStatement(f"Initialize_Bounded_{f.name}", [Variable("Ctx"), Variable("Length")]), CallStatement( f"Process_{f.name}", [ Slice( Selected(Variable("Ctx.Buffer"), "all"), Variable("Buffer_First"), Variable("Buffer_Last"), ), ], ), ], ) for f, t in message.types.items() if isinstance(t, Opaque) and bounded_setter_required(message, f) ], )
def create_internal_functions( self, message: Message, composite_fields: Sequence[Field] ) -> UnitPart: def result(field: Field, message: Message) -> NamedAggregate: aggregate: List[Tuple[str, Expr]] = [("Fld", Name(field.affixed_name))] if field in message.fields and isinstance(message.types[field], Scalar): aggregate.append( ( f"{field.name}_Value", Call( "Extract", [ Slice("Ctx.Buffer.all", Name("Buffer_First"), Name("Buffer_Last")), Name("Offset"), ], ), ) ) return NamedAggregate(*aggregate) return UnitPart( [], [ ExpressionFunctionDeclaration( FunctionSpecification( "Sufficient_Buffer_Length", "Boolean", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ), And( NotEqual(Name("Ctx.Buffer"), NULL), LessEqual(Name("Ctx.First"), Div(Last(self.types.bit_index), Number(2))), LessEqual( Call("Field_First", [Name("Ctx"), Name("Fld")]), Div(Last(self.types.bit_index), Number(2)), ), GreaterEqual(Call("Field_Length", [Name("Ctx"), Name("Fld")]), Number(0)), LessEqual( Call("Field_Length", [Name("Ctx"), Name("Fld")]), Div(Last(self.types.bit_length), Number(2)), ), LessEqual( Add( Call("Field_First", [Name("Ctx"), Name("Fld")]), Call("Field_Length", [Name("Ctx"), Name("Fld")]), ), Div(Last(self.types.bit_length), Number(2)), ), LessEqual( Name("Ctx.First"), Call("Field_First", [Name("Ctx"), Name("Fld")]) ), GreaterEqual( Name("Ctx.Last"), Call("Field_Last", [Name("Ctx"), Name("Fld")]) ), ), [ Precondition( And( Call("Has_Buffer", [Name("Ctx")]), Call("Valid_Next", [Name("Ctx"), Name("Fld")]), ) ) ], ), ExpressionFunctionDeclaration( FunctionSpecification( "Composite_Field", "Boolean", [Parameter(["Fld"], "Field")] ), Case( Name("Fld"), [ (Name(f.affixed_name), TRUE if f in composite_fields else FALSE) for f in message.fields ], ), ), SubprogramBody( FunctionSpecification( "Get_Field_Value", "Field_Dependent_Value", [Parameter(["Ctx"], "Context"), Parameter(["Fld"], "Field")], ), [ *self.common.field_bit_location_declarations(Name("Fld")), *self.common.field_byte_location_declarations(), ], [ ReturnStatement( Case( Name("Fld"), [ (Name(f.affixed_name), result(f, message)) for f in message.fields ], ) ) ], [ Precondition( AndThen( Call("Has_Buffer", [Name("Ctx")]), Call("Valid_Next", [Name("Ctx"), Name("Fld")]), Call("Sufficient_Buffer_Length", [Name("Ctx"), Name("Fld")]), ) ), Postcondition( Equal(Selected(Result("Get_Field_Value"), "Fld"), Name("Fld")) ), ], ), ], )
def specification(field: Field, field_type: Type) -> FunctionSpecification: return FunctionSpecification( f"Get_{field.name}", field_type.full_name, [Parameter(["Ctx"], "Context")] )