def _create_ptr_subtypes(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: unit = UnitPart(specification=[ Subtype( self._ptr_type(size), const.TYPES_BYTES_PTR, aspects=[ DynamicPredicate( OrElse( Equal(Variable(self._ptr_type(size)), Variable("null")), AndThen( Equal(First(self._ptr_type(size)), First(const.TYPES_INDEX)), Equal( Last(self._ptr_type(size)), Add(First(const.TYPES_INDEX), Number(size - 1)), ), ), )) ], ) for size in sorted({slot.size for slot in slots}) ]) self._declaration_context.append( WithClause(self._prefix * const.TYPES_PACKAGE)) self._declaration_context.append( UseTypeClause(self._prefix * const.TYPES_INDEX)) self._declaration_context.append( UseTypeClause(self._prefix * const.TYPES_BYTES_PTR)) return unit
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 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_verify_message_procedure( message: Message, context_invariant: Sequence[Expr]) -> UnitPart: specification = ProcedureSpecification( "Verify_Message", [InOutParameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification, [ Postcondition( And( Equal( Call("Has_Buffer", [Variable("Ctx")]), Old(Call("Has_Buffer", [Variable("Ctx")])), ), *context_invariant, )), ], ) ], [ SubprogramBody( specification, [], [ CallStatement( "Verify", [Variable("Ctx"), Variable(f.affixed_name)]) for f in message.fields ], ) ], )
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 create_composite_accessor_procedures(self, composite_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Get_{field.name}", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( And( VALID_CONTEXT, Call("Has_Buffer", [Name("Ctx")]), Call("Present", [Name("Ctx"), Name(f.affixed_name)]), ) ) ], [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{f.name}", [Parameter([f.name], self.types.bytes)] ) ) ], ) for f in composite_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], self.types.index, Call( self.types.byte_index, [Selected(Indexed("Ctx.Cursors", Name(f.affixed_name)), "First")], ), True, ), ObjectDeclaration( ["Last"], self.types.index, Call( self.types.byte_index, [Selected(Indexed("Ctx.Cursors", Name(f.affixed_name)), "Last")], ), True, ), ], [ CallStatement( f"Process_{f.name}", [Slice("Ctx.Buffer.all", Name("First"), Name("Last"))], ) ], ) for f in composite_fields ], )
def create_scalar_accessor_functions(scalar_fields: Mapping[Field, Scalar]) -> UnitPart: def specification(field: Field, field_type: Type) -> FunctionSpecification: return FunctionSpecification( f"Get_{field.name}", field_type.full_name, [Parameter(["Ctx"], "Context")] ) def result(field: Field, field_type: Type) -> Expr: value = Selected( Indexed("Ctx.Cursors", Name(field.affixed_name)), f"Value.{field.name}_Value" ) if isinstance(field_type, Enumeration): return Call("Convert", [value]) return value return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( And(VALID_CONTEXT, Call("Valid", [Name("Ctx"), Name(f.affixed_name)])) ) ], ) for f, t in scalar_fields.items() ], [ ExpressionFunctionDeclaration(specification(f, t), result(f, t)) for f, t in scalar_fields.items() ], )
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_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 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 _create_slots(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart: self._declaration_context.append( WithClause(self._prefix * const.TYPES_PACKAGE)) return UnitPart([ RecordType( "Slots", [ Component(self._slot_name(slot.slot_id), self._ptr_type(slot.size)) for slot in slots ], ) ])
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 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_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_memory(slots: Sequence[NumberedSlotInfo]) -> UnitPart: return UnitPart([ RecordType( "Memory", [ Component( f"Slot_{slot.slot_id}", Slice( Variable(const.TYPES_BYTES), First(const.TYPES_INDEX), Add(First(const.TYPES_INDEX), Number(slot.size - 1)), ), NamedAggregate(("others", Number(0))), aliased=True, ) for slot in slots ], ) ])
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_scalar_accessor_functions( self, scalar_fields: Mapping[Field, Scalar]) -> UnitPart: 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 result(field: Field) -> Expr: return Call( "To_Actual", [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(field.affixed_name)), f"Value.{field.name}_Value", ) ], ) return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( Call("Valid", [Variable("Ctx"), Variable(f.affixed_name)]), ) ], ) for f, t in scalar_fields.items() ], [ ExpressionFunctionDeclaration(specification(f, t), result(f)) for f, t in scalar_fields.items() ], )
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 __init__(self, session: Session, integration: Integration, prefix: str = "") -> None: self._session = session self._prefix = prefix self._declaration_context: List[ContextItem] = [] self._body_context: List[ContextItem] = [] self._allocation_slots: Dict[Location, int] = {} self._unit_part = UnitPart() self._integration = integration global_slots: List[SlotInfo] = self._allocate_global_slots() local_slots: List[SlotInfo] = self._allocate_local_slots() numbered_slots: List[NumberedSlotInfo] = [] count = 1 for slot in global_slots: numbered_slots.append( NumberedSlotInfo(slot.size, slot.locations, count, global_=True)) count += 1 for slot in local_slots: numbered_slots.append( NumberedSlotInfo(slot.size, slot.locations, count, global_=False)) count += 1 for slot in numbered_slots: for location in slot.locations: self._allocation_slots[location] = slot.slot_id self._create(numbered_slots) self._numbered_slots = numbered_slots
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_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar] ) -> UnitPart: return UnitPart( [], [ SubprogramBody( ProcedureSpecification( "Set_Field_Value", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], "Field_Dependent_Value"), OutParameter(["Fst", "Lst"], self.types.bit_index), ], ), [ *self.common.field_bit_location_declarations(Selected("Val", "Fld")), *self.common.field_byte_location_declarations(), ], [ Assignment("Fst", Name("First")), Assignment("Lst", Name("Last")), CaseStatement( Selected("Val", "Fld"), [ ( Name(f.affixed_name), [ CallStatement( "Insert", [ Selected("Val", f"{f.name}_Value"), Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), Name("Offset"), ], ) if f in scalar_fields else NullStatement() ], ) for f in message.all_fields ], ), ], [ Precondition( AndThen( Not(Constrained("Ctx")), Call("Has_Buffer", [Name("Ctx")]), In(Selected("Val", "Fld"), Range("Field")), Call("Valid_Next", [Name("Ctx"), Selected("Val", "Fld")]), self.common.sufficient_space_for_field_condition( Selected("Val", "Fld") ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Call( "Field_Last", [Name("Ctx"), Selected("Val", "Fld")], ), ), ) ] ), ), ) ), Postcondition( And( Call("Has_Buffer", [Name("Ctx")]), Equal( Name("Fst"), Call("Field_First", [Name("Ctx"), Selected("Val", "Fld")]), ), Equal( Name("Lst"), Call("Field_Last", [Name("Ctx"), Selected("Val", "Fld")]), ), GreaterEqual(Name("Fst"), Selected("Ctx", "First")), LessEqual(Name("Fst"), Add(Name("Lst"), Number(1))), LessEqual( Call(self.types.byte_index, [Name("Lst")]), Selected("Ctx", "Buffer_Last"), ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Name("Lst"), ), ) ] ), ), *[ Equal(e, Old(e)) for e in [ Selected("Ctx", "Buffer_First"), Selected("Ctx", "Buffer_Last"), Selected("Ctx", "First"), Selected("Ctx", "Cursors"), ] ], ) ), ], ) ], )
def create_composite_initialize_procedures(self, message: Message) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Initialize_{field.name}", [InOutParameter(["Ctx"], "Context")] ) def specification_bounded(field: Field) -> ProcedureSpecification: return ProcedureSpecification( f"Initialize_Bounded_{field.name}", [InOutParameter(["Ctx"], "Context"), Parameter(["Length"], self.types.bit_length)], ) 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]), ) ), ], ) 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]), ) ), ], ) 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)), self.common.initialize_field_statements(message, f), ) 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, ), ], self.common.initialize_field_statements(message, f), ) for f, t in message.types.items() if isinstance(t, Payload) and bounded_setter_required(message, f) ], )
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 create_scalar_setter_procedures( self, message: Message, scalar_fields: Mapping[Field, Scalar] ) -> UnitPart: def specification(field: Field, field_type: Type) -> ProcedureSpecification: type_name = ( field_type.enum_name if isinstance(field_type, Enumeration) and field_type.always_valid else field_type.name ) return ProcedureSpecification( f"Set_{field.name}", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], f"{message.package}.{type_name}"), ], ) return UnitPart( [ SubprogramDeclaration( specification(f, t), [ Precondition( AndThen( *self.setter_preconditions(f), Call( "Field_Condition", [ Name("Ctx"), Aggregate( Name(f.affixed_name), Name("Val") if not isinstance(t, Enumeration) else Call("Convert", [Name("Val")]), ), ], ), Call("Valid", [Name("Val")]) if not isinstance(t, Enumeration) else TRUE, self.common.sufficient_space_for_field_condition( Name(f.affixed_name) ), ) ), Postcondition( And( VALID_CONTEXT, Call("Has_Buffer", [Name("Ctx")]), Call("Valid", [Name("Ctx"), Name(f.affixed_name)]), Equal( Call(f"Get_{f.name}", [Name("Ctx")]), Aggregate(TRUE, Name("Val")) if isinstance(t, Enumeration) and t.always_valid else Name("Val"), ), *self.setter_postconditions(message, f, t), *[ Equal( Call("Cursor", [Name("Ctx"), Name(p.affixed_name)]), Old(Call("Cursor", [Name("Ctx"), Name(p.affixed_name)])), ) for p in message.predecessors(f) ], ) ), ], ) for f, t in scalar_fields.items() ], [ SubprogramBody( specification(f, t), [ ObjectDeclaration( ["Field_Value"], "Field_Dependent_Value", Aggregate( Name(f.affixed_name), Name("Val") if not isinstance(t, Enumeration) else Call("Convert", [Name("Val")]), ), True, ), ObjectDeclaration(["First", "Last"], self.types.bit_index), ], [ CallStatement( "Reset_Dependent_Fields", [Name("Ctx"), Name(f.affixed_name)], ), CallStatement( "Set_Field_Value", [Name("Ctx"), Name("Field_Value"), Name("First"), Name("Last")], ), Assignment( "Ctx", Aggregate( Selected("Ctx", "Buffer_First"), Selected("Ctx", "Buffer_Last"), Selected("Ctx", "First"), Name("Last"), Selected("Ctx", "Buffer"), Selected("Ctx", "Cursors"), ), ), Assignment( Indexed(Selected("Ctx", "Cursors"), Name(f.affixed_name)), NamedAggregate( ("State", Name("S_Valid")), ("First", Name("First")), ("Last", Name("Last")), ("Value", Name("Field_Value")), ( "Predecessor", Selected( Indexed(Selected("Ctx", "Cursors"), Name(f.affixed_name)), "Predecessor", ), ), ), ), Assignment( Indexed( Selected("Ctx", "Cursors"), Call("Successor", [Name("Ctx"), Name(f.affixed_name)]), ), NamedAggregate( ("State", Name("S_Invalid")), ("Predecessor", Name(f.affixed_name)), ), ), ], ) for f, t in scalar_fields.items() ], )
def create_composite_accessor_procedures( composite_fields: Sequence[Field]) -> UnitPart: def specification(field: Field) -> ProcedureSpecification: return ProcedureSpecification(f"Get_{field.name}", [Parameter(["Ctx"], "Context")]) return UnitPart( [ SubprogramDeclaration( specification(f), [ Precondition( And( Call("Has_Buffer", [Variable("Ctx")]), Call("Present", [ Variable("Ctx"), Variable(f.affixed_name) ]), )) ], [ FormalSubprogramDeclaration( ProcedureSpecification( f"Process_{f.name}", [Parameter([f.name], const.TYPES_BYTES)])) ], ) for f in composite_fields ], [ SubprogramBody( specification(f), [ ObjectDeclaration( ["First"], const.TYPES_INDEX, Call( const.TYPES_BYTE_INDEX, [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(f.affixed_name)), "First", ) ], ), True, ), ObjectDeclaration( ["Last"], const.TYPES_INDEX, Call( const.TYPES_BYTE_INDEX, [ Selected( Indexed(Variable("Ctx.Cursors"), Variable(f.affixed_name)), "Last", ) ], ), True, ), ], [ CallStatement( f"Process_{f.name}", [ Slice(Variable("Ctx.Buffer.all"), Variable("First"), Variable("Last")) ], ) ], ) for f in composite_fields ], )
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"), )), ], ), ], )