Hmm ... you actually bring up a good point here Lukasz. In the end doesn't the "try" flag simply make it an optional with a different type of optionality condition? Cause right now there are differences between optional and simple types in the way the references are stored. For example a "uint 8" is of type "short" for a simple and "Short" for an optional. I know that probably simple type references are probably not going to use "try", but perhaps we should instead make the optional field have an expression and/or the try flag.
This would make it a bit more consistent ... Sort of something like this: Classical: [optional MyCoolType 'coolOptionalField' 'expression'] New "try" option: [optional MyCoolType 'coolOptionalField' try] Combined "try" with "condition": [optional MyCoolType 'coolOptionalField' try 'expression'] What do you folks think? Chris -----Ursprüngliche Nachricht----- Von: Łukasz Dywicki <l...@code-house.org> Gesendet: Samstag, 25. September 2021 22:23 An: dev@plc4x.apache.org Betreff: Re: Changes on mspec: parameterized type refs, assert, try, const Hey Sebastian, Not that far ago we had a similar discussion. Yet then it was mainly about optionals. See "[DISCUSS] Change the way we use "optional". Back then we did not do any changes to mspec, just ranted about possible approach to make better use of optional fields. I remember that current mspec/code can't for example handle ie. a bacnet whois without all fields. Looking at your example I guess you try to solve that puzzle. I don't have any strong feelings here, but why not using optional field with additional "reset" flag? To me what rings a bell in your mail is an assumption that try is always followed by optional field. This tells me that 'try' should rather be a block than a field. By this way we will be able to pair these visually as well as handle situation when there is one try statement but multiple optional fields. Best, Łukasz On 24.09.2021 23:52, Sebastian Rühl wrote: > Hi together, > > I have some exciting changes in the pipeline regarding the mspec: > > 1. parameters on type refs > with that change it is now possible to target a discriminated child in > advance. > 2. assert keyword > with that change it is possible to throw a ParserAssertException > (in java, or errors in other languages). This field is similar to a const but > instead of a ParseException a ParserAssertException is thrown. In contrast to > a const the check expression can be dynamic (e.g. virtual fields now working > on develop) 3. try keyword to prefix fields: > with that change it is possible to try to parse some content and in case > an assert fails it resets the buffer. > 4. const is now extended to type reference > this change allows enums to be used as const values. > > All theses changes allow to encapsulate behavior in complex types so you > don't need to DRY. > > Here is a example working with bacnet: > ['0x07' BACnetUnconfirmedServiceRequestWhoHas > [try simple BACnetComplexTagUnsignedInteger ['0', > 'BACnetDataType.UNSIGNED_INTEGER' ] 'deviceInstanceRangeLowLimit' ] > [optional BACnetComplexTagUnsignedInteger ['1', > 'BACnetDataType.UNSIGNED_INTEGER' ] 'deviceInstanceRangeHighLimit' > 'deviceInstanceRangeLowLimit != null'] > [try simple BACnetComplexTagOctetString ['2', > 'BACnetDataType.OCTET_STRING' ] 'objectIdentifier' ] > [optional BACnetComplexTagOctetString ['3', > 'BACnetDataType.OCTET_STRING' ] 'objectName' 'objectIdentifier == null' ] > ] > > The logic if a type matches is asserted in the type itself. The second > optional implies when the first element appears the second must be present. > The last one tries to read and if it fails it uses the second type. > > Here is the snippet from the parent type: > > [discriminatedType 'BACnetComplexTag' [uint 4 'tagNumberArgument', > BACnetDataType 'dataType'] > [assert uint 4 'tagNumber' > 'tagNumberArgument' ] > [const TagClass 'tagClass' > 'TagClass.CONTEXT_SPECIFIC_TAGS' ] > [simple uint 3 'lengthValueType' > ] > ..... > [virtual uint 32 'actualLength' 'lengthValueType == 5 > ....'] > [typeSwitch 'dataType' > .... > ['OCTET_STRING' BACnetComplexTagOctetString [uint 32 'actualLength'] > // TODO: The reader expects int but uint32 get's mapped to long > so even uint32 would easily overflow... > [virtual uint 16 > 'actualLengthInBit' 'actualLength * 8'] > [simple string 'actualLengthInBit' 'ASCII' 'theString'] > ] > > Would love to hear some opinions! If there are no objections I would push > this change to develop soon. > > - Sebastian > > PatchContent: > Index: > code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/p > lugins/codegenerator/language/mspec/MSpec.g4 > <+>UTF-8 > =================================================================== > diff --git > a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 > > b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 > --- > a/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 > (revision ef35531d5a872f29dccddb3a11a135b166958185) > +++ > b/code-generation/protocol-base-mspec/src/main/antlr4/org/apache/plc4x/plugins/codegenerator/language/mspec/MSpec.g4 > (date 1632518519426) > @@ -34,7 +34,7 @@ > ; > > fieldDefinition > - : LBRACKET field (LBRACKET params=multipleExpressions RBRACKET)? > RBRACKET > + : LBRACKET tryParse? field (LBRACKET params=multipleExpressions > + RBRACKET)? RBRACKET > ; > > dataIoDefinition > @@ -49,6 +49,7 @@ > | discriminatorField > | enumField > | implicitField > + | assertField > | manualArrayField > | manualField > | optionalField > @@ -73,7 +74,7 @@ > ; > > constField > - : 'const' type=dataType name=idExpression expected=expression > + : 'const' type=typeReference name=idExpression expected=expression > ; > > discriminatorField > @@ -88,6 +89,10 @@ > : 'implicit' type=dataType name=idExpression serializeExpression=expression > ; > > +assertField > + : 'assert' type=typeReference name=idExpression condition=expression > +; > + > manualArrayField > : 'manualArray' type=typeReference name=idExpression > loopType=ARRAY_LOOP_TYPE loopExpression=expression parseExpression=expression > serializeExpression=expression lengthExpression=expression > ; > @@ -129,7 +134,7 @@ > ; > > typeReference > - : complexTypeReference=IDENTIFIER_LITERAL > + : complexTypeReference=IDENTIFIER_LITERAL (LBRACKET > params=multipleExpressions RBRACKET)? > | simpleTypeReference=dataType > ; > > @@ -150,6 +155,10 @@ > | base='dateTime' > ; > > +tryParse > + : 'try' > + ; > + > argument > : type=typeReference name=idExpression > ; >