diff --git a/.gitignore b/.gitignore index 3d880735c..06f5da8e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +shared_workdir/ .metals .vscode .idea diff --git a/BackendAst/DAstACN.fs b/BackendAst/DAstACN.fs index 5c934bf08..cf505a1b6 100644 --- a/BackendAst/DAstACN.fs +++ b/BackendAst/DAstACN.fs @@ -89,12 +89,21 @@ let getDeterminantTypeCheckEqual (lm:LanguageMacros) (det:Determinant) = let multiAcnUpdate_checkEqual_str = lm.acn.MultiAcnUpdate_checkEqual_str getDeterminant_macro det multiAcnUpdate_checkEqual_pri multiAcnUpdate_checkEqual_str -let handleSavePosition (funcBody:State-> ErrorCode->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> ((AcnFuncBodyResult option)*State)) savePosition c_name (typeId:ReferenceToType) (lm:LanguageMacros) (codec:CommonTypes.Codec) prms p = + +type FuncBody = State -> ErrorCode -> (AcnGenericTypes.RelativePath * AcnGenericTypes.AcnParameter) list -> NestingScope -> CallerScope -> (AcnFuncBodyResult option) * State +type FuncBodyStateless = Codec -> (AcnGenericTypes.RelativePath * AcnGenericTypes.AcnParameter) list -> NestingScope -> CallerScope -> AcnFuncBodyResult option + +let handleSavePosition (funcBody: FuncBody) + (savePosition: bool) + (c_name: string) + (typeId:ReferenceToType) + (lm:LanguageMacros) + (codec:CommonTypes.Codec): FuncBody = match savePosition with | false -> funcBody | true -> - let newFuncBody st errCode prms p = - let content, ns1a = funcBody st errCode prms p + let newFuncBody st errCode prms nestingScope p = + let content, ns1a = funcBody st errCode prms nestingScope p let sequence_save_bitstream = lm.acn.sequence_save_bitstream let lvName = sprintf "bitStreamPositions_%d" (typeId.SequenceOfLevel + 1) let savePositionStatement = sequence_save_bitstream lvName c_name codec @@ -105,11 +114,15 @@ let handleSavePosition (funcBody:State-> ErrorCode->((AcnGenericTypes.RelativePa Some {bodyResult with funcBody = funcBodyStr} | None -> let funcBodyStr = savePositionStatement - Some {funcBody = funcBodyStr; errCodes =[]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None} + Some {funcBody = funcBodyStr; errCodes =[]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None; typeEncodingKind = None} newContent, ns1a newFuncBody -let handleAlignmentForAsn1Types (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (acnAlignment: AcnAlignment option ) (funcBody:State-> ErrorCode->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> ((AcnFuncBodyResult option)*State)) = +let handleAlignmentForAsn1Types (r:Asn1AcnAst.AstRoot) + (lm:LanguageMacros) + (codec:CommonTypes.Codec) + (acnAlignment: AcnAlignment option) + (funcBody: FuncBody): FuncBody = let alignToNext = lm.acn.alignToNext match acnAlignment with | None -> funcBody @@ -128,21 +141,24 @@ let handleAlignmentForAsn1Types (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (code match ST.lang with | Scala -> "Int", 32I | _ -> "NextDWord", 32I - let newFuncBody st errCode prms p = - let content, ns1a = funcBody st errCode prms p + let newFuncBody st errCode prms nestingScope p = + let content, ns1a = funcBody st errCode prms nestingScope p let newContent = match content with | Some bodyResult -> - let funcBodyStr = alignToNext bodyResult.funcBody alStr nAlignmentVal codec + let funcBodyStr = alignToNext bodyResult.funcBody alStr nAlignmentVal nestingScope.acnOffset (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) (bigint nestingScope.nestingLevel - 1I) (bigint nestingScope.nestingIx) nestingScope.acnRelativeOffset codec Some {bodyResult with funcBody = funcBodyStr} | None -> - let funcBodyStr = alignToNext "" alStr nAlignmentVal codec - Some {funcBody = funcBodyStr; errCodes =[errCode]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None} + let funcBodyStr = alignToNext "" alStr nAlignmentVal nestingScope.acnOffset (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) (bigint nestingScope.nestingLevel - 1I) (bigint nestingScope.nestingIx) nestingScope.acnRelativeOffset codec + Some {funcBody = funcBodyStr; errCodes =[errCode]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None; typeEncodingKind = None} newContent, ns1a newFuncBody -let handleAlignmentForAcnTypes (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (acnAlignment : AcnAlignment option ) (funcBody:CommonTypes.Codec -> ((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> (AcnFuncBodyResult option)) = - let alignToNext = lm.acn.alignToNext +let handleAlignmentForAcnTypes (r:Asn1AcnAst.AstRoot) + (lm:LanguageMacros) + (acnAlignment : AcnAlignment option) + (funcBody: FuncBodyStateless): FuncBodyStateless = + let alignToNext = lm.acn.alignToNext match acnAlignment with | None -> funcBody | Some al -> @@ -151,16 +167,16 @@ let handleAlignmentForAcnTypes (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (acn | AcnGenericTypes.NextByte -> "NextByte", 8I | AcnGenericTypes.NextWord -> "NextWord", 16I | AcnGenericTypes.NextDWord -> "NextDWord", 32I - let newFuncBody (codec:CommonTypes.Codec) prms p = - let content = funcBody codec prms p + let newFuncBody (codec:CommonTypes.Codec) (prms: (RelativePath * AcnParameter) list) (nestingScope: NestingScope) (p: CallerScope) = + let content = funcBody codec prms nestingScope p let newContent = match content with | Some bodyResult -> - let funcBodyStr = alignToNext bodyResult.funcBody alStr nAlignmentVal codec + let funcBodyStr = alignToNext bodyResult.funcBody alStr nAlignmentVal nestingScope.acnOffset (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) (bigint nestingScope.nestingLevel - 1I) (bigint nestingScope.nestingIx) nestingScope.acnRelativeOffset codec Some {bodyResult with funcBody = funcBodyStr} | None -> - let funcBodyStr = alignToNext "" alStr nAlignmentVal codec - Some {funcBody = funcBodyStr; errCodes =[]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None} + let funcBodyStr = alignToNext "" alStr nAlignmentVal nestingScope.acnOffset (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) (bigint nestingScope.nestingLevel - 1I) (bigint nestingScope.nestingIx) nestingScope.acnRelativeOffset codec + Some {funcBody = funcBodyStr; errCodes =[]; localVariables = []; bValIsUnReferenced= true; bBsIsUnReferenced=false; resultExpr = None; typeEncodingKind = None} newContent newFuncBody @@ -222,18 +238,18 @@ let adaptArgumentValue = DAstUPer.adaptArgumentValue let joinedOrAsIdentifier = DAstUPer.joinedOrAsIdentifier -let private createAcnFunction (r:Asn1AcnAst.AstRoot) - (lm:LanguageMacros) - (codec:CommonTypes.Codec) - (t:Asn1AcnAst.Asn1Type) - (typeDefinition:TypeDefinitionOrReference) +let private createAcnFunction (r: Asn1AcnAst.AstRoot) + (lm: LanguageMacros) + (codec: CommonTypes.Codec) + (t: Asn1AcnAst.Asn1Type) + (typeDefinition: TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) - (funcBody:State-> ErrorCode->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> ((AcnFuncBodyResult option)*State)) + (funcBody: FuncBody) isTestVaseValid - (icdAux:IcdArgAux) + (icdAux: IcdArgAux) (soSparkAnnotations: string option) (funcDefAnnots: string list) - (us:State) = + (us: State) = let td = lm.lg.getTypeDefinition t.FT_TypeDefinition let funcNameBase = td.typeName + "_ACN" let funcNameAndtasInfo = @@ -252,10 +268,14 @@ let private createAcnFunction (r:Asn1AcnAst.AstRoot) let EmitTypeAssignment_primitive_def = lm.acn.EmitTypeAssignment_primitive_def let EmitTypeAssignment_def_err_code = lm.acn.EmitTypeAssignment_def_err_code - let funcBodyAsSeqComp st prms p c_name : ((AcnFuncBodyResult option)*State) = - let funcBody = handleSavePosition funcBody t.SaveBitStreamPosition c_name t.id lm codec prms p + let funcBodyAsSeqComp (st: State) + (prms: (RelativePath * AcnParameter) list) + (nestingScope: NestingScope) + (p: CallerScope) + (c_name: string): ((AcnFuncBodyResult option)*State) = + let funcBody = handleSavePosition funcBody t.SaveBitStreamPosition c_name t.id lm codec let ret = handleAlignmentForAsn1Types r lm codec t.acnAlignment funcBody - ret st errCode prms p + ret st errCode prms nestingScope p let funcBody = handleAlignmentForAsn1Types r lm codec t.acnAlignment funcBody @@ -266,17 +286,17 @@ let private createAcnFunction (r:Asn1AcnAst.AstRoot) let sInitialExp = "" let func, funcDef,ns2 = match funcNameAndtasInfo with - | None -> None, None, ns - | Some funcName -> + | None -> None, None, ns + | Some funcName -> let precondAnnots = lm.lg.generatePrecond ACN t let postcondAnnots = lm.lg.generatePostcond ACN funcNameBase p t codec - let content, ns1a = funcBody ns errCode [] p + let content, ns1a = funcBody ns errCode [] (NestingScope.init t.acnMaxSizeInBits t.uperMaxSizeInBits) p let bodyResult_funcBody, errCodes, bodyResult_localVariables, bBsIsUnreferenced, bVarNameIsUnreferenced = match content with - | None -> + | None -> let emptyStatement = lm.lg.emptyStatement emptyStatement, [], [], true, isValidFuncName.IsNone - | Some bodyResult -> + | Some bodyResult -> bodyResult.funcBody, bodyResult.errCodes, bodyResult.localVariables, bodyResult.bBsIsUnReferenced, bodyResult.bValIsUnReferenced let handleAcnParameter (p:AcnGenericTypes.AcnParameter) = @@ -331,8 +351,16 @@ let private createAcnFunction (r:Asn1AcnAst.AstRoot) } ret, ns3 +type AcnIntegerFuncBody = ErrorCode -> ((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> NestingScope -> CallerScope -> (AcnFuncBodyResult option) -let private createAcnIntegerFunctionInternal (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (uperRange : BigIntegerUperRange) (intClass:Asn1AcnAst.IntegerClass) acnEncodingClass (uperfuncBody : ErrorCode -> CallerScope -> (UPERFuncBodyResult option)) (soMF:string option, soMFM:string option) : (ErrorCode -> ((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> (AcnFuncBodyResult option)) = +let private createAcnIntegerFunctionInternal (r:Asn1AcnAst.AstRoot) + (lm:LanguageMacros) + (codec:CommonTypes.Codec) + (uperRange : BigIntegerUperRange) + (intClass:Asn1AcnAst.IntegerClass) + (acnEncodingClass: IntEncodingClass) + (uperfuncBody : ErrorCode -> NestingScope -> CallerScope -> (UPERFuncBodyResult option)) + (soMF:string option, soMFM:string option): AcnIntegerFuncBody = let PositiveInteger_ConstSize_8 = lm.acn.PositiveInteger_ConstSize_8 let PositiveInteger_ConstSize_big_endian_16 = lm.acn.PositiveInteger_ConstSize_big_endian_16 let PositiveInteger_ConstSize_little_endian_16 = lm.acn.PositiveInteger_ConstSize_little_endian_16 @@ -357,9 +385,6 @@ let private createAcnIntegerFunctionInternal (r:Asn1AcnAst.AstRoot) (lm:Language let BCD_ConstSize = lm.acn.BCD_ConstSize let BCD_VarSize_NullTerminated = lm.acn.BCD_VarSize_NullTerminated - //let errCodeName = ToC ("ERR_ACN" + (codec.suffix.ToUpper()) + "_" + ((typeId.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm"))) - //let errCodeValue = us.currErrCode - //let errCode = {ErrorCode.errCodeName = errCodeName; errCodeValue = errCodeValue} let nUperMin, nUperMax = match uperRange with | Concrete(a,b) -> a,b @@ -367,7 +392,10 @@ let private createAcnIntegerFunctionInternal (r:Asn1AcnAst.AstRoot) (lm:Language | PosInf(a) -> a, r.args.IntMax (a>=0I) | Full -> r.args.SIntMin, r.args.SIntMax - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) + (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) + (nestingScope: NestingScope) + (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let uIntActualMax (nBits:int) = let a = 2I**nBits - 1I @@ -381,38 +409,77 @@ let private createAcnIntegerFunctionInternal (r:Asn1AcnAst.AstRoot) (lm:Language let sSsuffix = DAstUPer.getIntDecFuncSuffix intClass let castPp encFuncBits = DAstUPer.castPp r lm codec pp intClass encFuncBits let word_size_in_bits = (int r.args.integerSizeInBytes)*8 - //let soMF = match let funcBodyContent = match acnEncodingClass with - |Asn1AcnAst.Integer_uPER -> uperfuncBody errCode p |> Option.map(fun x -> x.funcBody, x.errCodes, x.bValIsUnReferenced, x.bBsIsUnReferenced) - |Asn1AcnAst.PositiveInteger_ConstSize_8 -> Some(PositiveInteger_ConstSize_8 (castPp 8) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 8) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_16 -> Some(PositiveInteger_ConstSize_big_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 16) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_16 -> Some(PositiveInteger_ConstSize_little_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 16) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_32 -> Some(PositiveInteger_ConstSize_big_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 32) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_32 -> Some(PositiveInteger_ConstSize_little_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 32) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_64 -> Some(PositiveInteger_ConstSize_big_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 64) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_64 -> Some(PositiveInteger_ConstSize_little_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 64) codec, [errCode], false, false) - |Asn1AcnAst.PositiveInteger_ConstSize bitSize -> Some(PositiveInteger_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName ( bitSize) soMF soMFM (max 0I nUperMin) (uIntActualMax (int bitSize)) codec, [errCode], false, false) - - |Asn1AcnAst.TwosComplement_ConstSize_8 -> Some(TwosComplement_ConstSize_8 (castPp 8) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 8) (sIntActualMax 8) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_big_endian_16 -> Some(TwosComplement_ConstSize_big_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 16) (sIntActualMax 16) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_little_endian_16 -> Some(TwosComplement_ConstSize_little_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 16) (sIntActualMax 16) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_big_endian_32 -> Some(TwosComplement_ConstSize_big_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 32) (sIntActualMax 32) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_little_endian_32 -> Some(TwosComplement_ConstSize_little_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 32) (sIntActualMax 32) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_big_endian_64 -> Some(TwosComplement_ConstSize_big_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 64) (sIntActualMax 64) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize_little_endian_64 -> Some(TwosComplement_ConstSize_little_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 64) (sIntActualMax 64) codec, [errCode], false, false) - |Asn1AcnAst.TwosComplement_ConstSize bitSize -> Some(TwosComplement_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM ( bitSize) (sIntActualMin (int bitSize)) (sIntActualMax (int bitSize)) codec, [errCode], false, false) - - |Asn1AcnAst.ASCII_ConstSize size -> Some(ASCII_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax ((size)/8I) codec, [errCode], false, false) - |Asn1AcnAst.ASCII_VarSize_NullTerminated nullBytes -> Some(ASCII_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax nullBytes codec, [errCode], false, false) - |Asn1AcnAst.ASCII_UINT_ConstSize size -> Some(ASCII_UINT_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax (( size)/8I) codec, [errCode], false, false) - |Asn1AcnAst.ASCII_UINT_VarSize_NullTerminated nullBytes -> Some(ASCII_UINT_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax nullBytes codec, [errCode], false, false) - |Asn1AcnAst.BCD_ConstSize size -> Some(BCD_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax (( size)/4I) codec, [errCode], false, false) - |Asn1AcnAst.BCD_VarSize_NullTerminated nullBytes -> Some(BCD_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax codec, [errCode], false, false) + |Asn1AcnAst.Integer_uPER -> + uperfuncBody errCode nestingScope p |> Option.map(fun x -> x.funcBody, x.errCodes, x.bValIsUnReferenced, x.bBsIsUnReferenced, x.typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_8 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = Byte} + Some(PositiveInteger_ConstSize_8 (castPp 8) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 8) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_16 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = BigEndian S16} + Some(PositiveInteger_ConstSize_big_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 16) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_16 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = LittleEndian S16} + Some(PositiveInteger_ConstSize_little_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 16) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_32 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = BigEndian S32} + Some(PositiveInteger_ConstSize_big_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 32) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_32 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = LittleEndian S32} + Some(PositiveInteger_ConstSize_little_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 32) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_big_endian_64 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = BigEndian S64} + Some(PositiveInteger_ConstSize_big_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 64) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize_little_endian_64 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = LittleEndian S64} + Some(PositiveInteger_ConstSize_little_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (max 0I nUperMin) (uIntActualMax 64) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.PositiveInteger_ConstSize bitSize -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = Positive; endianness = Unbounded} + Some(PositiveInteger_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName ( bitSize) soMF soMFM (max 0I nUperMin) (uIntActualMax (int bitSize)) codec, [errCode], false, false, Some typeEncodingKind) + + |Asn1AcnAst.TwosComplement_ConstSize_8 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = Byte} + Some(TwosComplement_ConstSize_8 (castPp 8) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 8) (sIntActualMax 8) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_big_endian_16 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = BigEndian S16} + Some(TwosComplement_ConstSize_big_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 16) (sIntActualMax 16) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_little_endian_16 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = LittleEndian S16} + Some(TwosComplement_ConstSize_little_endian_16 (castPp 16) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 16) (sIntActualMax 16) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_big_endian_32 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = BigEndian S32} + Some(TwosComplement_ConstSize_big_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 32) (sIntActualMax 32) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_little_endian_32 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = LittleEndian S32} + Some(TwosComplement_ConstSize_little_endian_32 (castPp 32) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 32) (sIntActualMax 32) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_big_endian_64 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = BigEndian S64} + Some(TwosComplement_ConstSize_big_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 64) (sIntActualMax 64) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize_little_endian_64 -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = LittleEndian S64} + Some(TwosComplement_ConstSize_little_endian_64 (castPp 64) sSsuffix errCode.errCodeName soMF soMFM (sIntActualMin 64) (sIntActualMax 64) codec, [errCode], false, false, Some typeEncodingKind) + |Asn1AcnAst.TwosComplement_ConstSize bitSize -> + let typeEncodingKind = AcnIntegerEncodingType {signedness = TwosComplement; endianness = Unbounded} + Some(TwosComplement_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM ( bitSize) (sIntActualMin (int bitSize)) (sIntActualMax (int bitSize)) codec, [errCode], false, false, Some typeEncodingKind) + + |Asn1AcnAst.ASCII_ConstSize size -> + Some(ASCII_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax ((size)/8I) codec, [errCode], false, false, Some Placeholder) // TODO: Placeholder + |Asn1AcnAst.ASCII_VarSize_NullTerminated nullBytes -> + Some(ASCII_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax nullBytes codec, [errCode], false, false, Some Placeholder) + |Asn1AcnAst.ASCII_UINT_ConstSize size -> + Some(ASCII_UINT_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax (( size)/8I) codec, [errCode], false, false, Some Placeholder) + |Asn1AcnAst.ASCII_UINT_VarSize_NullTerminated nullBytes -> + Some(ASCII_UINT_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax nullBytes codec, [errCode], false, false, Some Placeholder) + |Asn1AcnAst.BCD_ConstSize size -> + Some(BCD_ConstSize (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax (( size)/4I) codec, [errCode], false, false, Some Placeholder) + |Asn1AcnAst.BCD_VarSize_NullTerminated nullBytes -> + Some(BCD_VarSize_NullTerminated (castPp word_size_in_bits) sSsuffix errCode.errCodeName soMF soMFM nUperMin nUperMax codec, [errCode], false, false, Some Placeholder) + match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, bValIsUnReferenced, bBsIsUnReferenced ) -> - Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= bValIsUnReferenced; bBsIsUnReferenced=bBsIsUnReferenced; resultExpr = resultExpr}) + | Some (funcBodyContent,errCodes, bValIsUnReferenced, bBsIsUnReferenced, typeEncodingKind ) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= bValIsUnReferenced; bBsIsUnReferenced=bBsIsUnReferenced; resultExpr = resultExpr; typeEncodingKind = typeEncodingKind}) funcBody let getMappingFunctionModule (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (soMapFuncName:string option) = @@ -431,8 +498,8 @@ let createAcnIntegerFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let errCodeName = ToC ("ERR_ACN" + (codec.suffix.ToUpper()) + "_" + ((typeId.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm"))) let errCode, ns = getNextValidErrorCode us errCodeName None - let uperFuncBody (errCode) (p:CallerScope) = - DAstUPer.getIntfuncBodyByCons r lm codec t.uperRange t.Location (getAcnIntegerClass r.args t) (t.cons) (t.cons@t.withcons) errCode p + let uperFuncBody (errCode) (nestingScope: NestingScope) (p:CallerScope) = + DAstUPer.getIntfuncBodyByCons r lm codec t.uperRange t.Location (getAcnIntegerClass r.args t) (t.cons) (t.cons@t.withcons) typeId errCode nestingScope p let soMapFunMod, soMapFunc = match t.acnProperties.mappingFunction with | Some (MappingFunction (soMapFunMod, mapFncName)) -> @@ -466,7 +533,7 @@ let createIntegerFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Comm let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=sAsn1Constraints; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let createAcnChildIcdFunction (ch:AcnChild) = let icd fieldName comments = @@ -490,7 +557,7 @@ let createEnumCommon (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTyp let uperRange = (Concrete (min,max)) let intTypeClass = getIntEncodingClassByUperRange r.args uperRange let rtlIntType = (DAstTypeDefinition.getIntegerTypeByClass lm intTypeClass)() - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let td = (lm.lg.getEnumTypeDefinition o.typeDef).longTypedefName2 lm.lg.hasModules (ToC p.modName) let localVar, intVal = let varName = $"intVal_{ToC p.arg.asIdentifier}" @@ -501,25 +568,32 @@ let createEnumCommon (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTyp lv, varName let pVal = {CallerScope.modName = typeId.ModName; arg = Selection.valueEmptyPath intVal} let intFuncBody = - let uperInt (errCode:ErrorCode) (p:CallerScope) = + let uperInt (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let castPp = DAstUPer.castPp r lm codec pp intTypeClass let sSsuffix = DAstUPer.getIntDecFuncSuffix intTypeClass let word_size_in_bits = (int r.args.integerSizeInBytes)*8 - let funcBody = IntFullyConstraintPos (castPp word_size_in_bits) min max (GetNumberOfBitsForNonNegativeInteger (max-min)) sSsuffix errCode.errCodeName codec - Some({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables= []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + let nbits = GetNumberOfBitsForNonNegativeInteger (max-min) + let rangeAssert = + match typeId.topLevelTas with + | Some tasInfo -> + lm.lg.generateIntFullyConstraintRangeAssert (ToC (r.args.TypePrefix + tasInfo.tasName)) p codec + | None -> None + let funcBody = IntFullyConstraintPos (castPp word_size_in_bits) min max nbits sSsuffix errCode.errCodeName rangeAssert codec + Some({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables= []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (Asn1IntegerEncodingType (Some (FullyConstrainedPositive (min, max))))}) createAcnIntegerFunctionInternal r lm codec (Concrete (min,max)) intTypeClass o.acnEncodingClass uperInt (None, None) let funcBodyContent = - match intFuncBody errCode acnArgs pVal with + match intFuncBody errCode acnArgs nestingScope pVal with | None -> None | Some intAcnFuncBdResult -> let arrItems = o.items |> List.map(fun it -> let enumClassName = extractEnumClassName "" it.scala_name it.Name.Value Enumerated_item (lm.lg.getValue p.arg) (lm.lg.getNamedItemBackendName (Some defOrRef) it) enumClassName it.acnEncodeValue (lm.lg.intValueToString it.acnEncodeValue intTypeClass) intVal codec) - Some (EnumeratedEncValues (lm.lg.getValue p.arg) td arrItems intAcnFuncBdResult.funcBody errCode.errCodeName sFirstItemName intVal codec, intAcnFuncBdResult.resultExpr, intAcnFuncBdResult.errCodes, localVar@intAcnFuncBdResult.localVariables) + Some (EnumeratedEncValues (lm.lg.getValue p.arg) td arrItems intAcnFuncBdResult.funcBody errCode.errCodeName sFirstItemName intVal codec, intAcnFuncBdResult.resultExpr, intAcnFuncBdResult.errCodes, localVar@intAcnFuncBdResult.localVariables, intAcnFuncBdResult.typeEncodingKind) match funcBodyContent with | None -> None - | Some (funcBodyContent, resultExpr, errCodes, localVariables) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent, resultExpr, errCodes, localVariables, typeEncodingKind) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) funcBody let enumComment stgFileName (o:Asn1AcnAst.Enumerated) = @@ -545,7 +619,7 @@ let createEnumeratedFunction (r:Asn1AcnAst.AstRoot) (icdStgFileName:string) (lm: let newComments = comments@[enumComment icdStgFileName o] [{IcdRow.fieldName = fieldName; comments = newComments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None;} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let createAcnEnumeratedFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (typeId : ReferenceToType) (t:Asn1AcnAst.AcnReferenceToEnumerated) (defOrRef:TypeDefinitionOrReference) (us:State) = @@ -556,8 +630,6 @@ let createAcnEnumeratedFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (code let funcBody = createEnumCommon r lm codec typeId t.enumerated defOrRef typeDefinitionName (funcBody errCode), ns - - let createRealFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Real) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (uperFunc: UPerFunction) (us:State) = let Real_32_big_endian = lm.acn.Real_32_big_endian let Real_64_big_endian = lm.acn.Real_64_big_endian @@ -571,20 +643,20 @@ let createRealFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonT | ASN1SCC_FP64 -> "" - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let castPp = DAstUPer.castRPp lm codec (o.getClass r.args) pp let funcBodyContent = match o.acnEncodingClass with - | Real_IEEE754_32_big_endian -> Some (Real_32_big_endian castPp sSuffix errCode.errCodeName codec, [errCode]) - | Real_IEEE754_64_big_endian -> Some (Real_64_big_endian pp errCode.errCodeName codec, [errCode]) - | Real_IEEE754_32_little_endian -> Some (Real_32_little_endian castPp sSuffix errCode.errCodeName codec, [errCode]) - | Real_IEEE754_64_little_endian -> Some (Real_64_little_endian pp errCode.errCodeName codec, [errCode]) - | Real_uPER -> uperFunc.funcBody_e errCode p |> Option.map(fun x -> x.funcBody, x.errCodes) + | Real_IEEE754_32_big_endian -> Some (Real_32_big_endian castPp sSuffix errCode.errCodeName codec, [errCode], Some (AcnRealEncodingType BigEndian32)) + | Real_IEEE754_64_big_endian -> Some (Real_64_big_endian pp errCode.errCodeName codec, [errCode], Some (AcnRealEncodingType BigEndian64)) + | Real_IEEE754_32_little_endian -> Some (Real_32_little_endian castPp sSuffix errCode.errCodeName codec, [errCode], Some (AcnRealEncodingType LittleEndian32)) + | Real_IEEE754_64_little_endian -> Some (Real_64_little_endian pp errCode.errCodeName codec, [errCode], Some (AcnRealEncodingType LittleEndian64)) + | Real_uPER -> uperFunc.funcBody_e errCode nestingScope p |> Option.map(fun x -> x.funcBody, x.errCodes, x.typeEncodingKind) match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, typeEncodingKind) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] @@ -593,35 +665,35 @@ let createRealFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonT match ST.lang with | Scala -> ["extern"] | _ -> [] - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations annots us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations annots us let createObjectIdentifierFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.ObjectIdentifier) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (uperFunc: UPerFunction) (us:State) = - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let funcBodyContent = - uperFunc.funcBody_e errCode p |> Option.map(fun x -> x.funcBody, x.errCodes, x.resultExpr) + uperFunc.funcBody_e errCode nestingScope p |> Option.map(fun x -> x.funcBody, x.errCodes, x.resultExpr, x.typeEncodingKind) match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, resultExpr) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, resultExpr, typeEncodingKind) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let createTimeTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.TimeType) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (uperFunc: UPerFunction) (us:State) = - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let funcBodyContent = - uperFunc.funcBody_e errCode p |> Option.map(fun x -> x.funcBody, x.errCodes, x.resultExpr) + uperFunc.funcBody_e errCode nestingScope p |> Option.map(fun x -> x.funcBody, x.errCodes, x.resultExpr, x.typeEncodingKind) match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, resultExpr) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, resultExpr, typeEncodingKind) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None;} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let nestChildItems (lm:LanguageMacros) (codec:CommonTypes.Codec) children = @@ -632,23 +704,23 @@ let createAcnBooleanFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let errCodeName = ToC ("ERR_ACN" + (codec.suffix.ToUpper()) + "_" + ((typeId.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm"))) let errCode, ns = getNextValidErrorCode us errCodeName None - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let Boolean = lm.uper.Boolean let funcBodyContent = Boolean pp errCode.errCodeName codec - Some {AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr} + Some {AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnBooleanEncodingType None)} (funcBody errCode), ns let createBooleanFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Boolean) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : AcnFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let Boolean = lm.uper.Boolean let acnBoolean = lm.acn.Boolean - let funcBodyContent, resultExpr = + let funcBodyContent, resultExpr, typeEncodingKind = match o.acnProperties.encodingPattern with | None -> let pp, resultExpr = adaptArgument lm codec p - Boolean pp errCode.errCodeName codec, resultExpr + Boolean pp errCode.errCodeName codec, resultExpr, AcnBooleanEncodingType None | Some pattern -> let pvalue, ptr, resultExpr = match codec, lm.lg.decodingKind with @@ -661,14 +733,14 @@ let createBooleanFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Comm let arrTrueValueAsByteArray = arrBytes |> Array.map (~~~) let arrFalseValueAsByteArray = arrBytes let nSize = pattern.bitVal.Value.Length - acnBoolean pvalue ptr pattern.isTrue (BigInteger nSize) arrTrueValueAsByteArray arrFalseValueAsByteArray arrBits errCode.errCodeName codec, resultExpr + acnBoolean pvalue ptr pattern.isTrue (BigInteger nSize) arrTrueValueAsByteArray arrFalseValueAsByteArray arrBits errCode.errCodeName codec, resultExpr, AcnBooleanEncodingType (Some pattern) - {AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some typeEncodingKind} let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> Some (funcBody e acnArgs p), us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> Some (funcBody e acnArgs nestingScope p), us) (fun atc -> true) icd soSparkAnnotations [] us @@ -677,7 +749,7 @@ let createAcnNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec: let errCodeName = ToC ("ERR_ACN" + (codec.suffix.ToUpper()) + "_" + ((typeId.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm"))) let errCode, ns = getNextValidErrorCode us errCodeName None - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let nullType = lm.acn.Null_pattern2 match o.acnProperties.encodingPattern with @@ -695,11 +767,11 @@ let createAcnNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec: let arrsBits = bitStringPattern.ToCharArray() |> Seq.mapi(fun i x -> ((i+1).ToString()) + "=>" + if x='0' then "0" else "1") |> Seq.toList arrsBits,arrBytes,(BigInteger bitStringPattern.Length) let ret = nullType pp arrBytes nBitsSize arrsBits errCode.errCodeName o.acnProperties.savePosition codec - Some ({AcnFuncBodyResult.funcBody = ret; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + Some ({AcnFuncBodyResult.funcBody = ret; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnNullEncodingType (Some encPattern))}) (funcBody errCode), ns let createNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.NullType) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let nullType = lm.acn.Null_pattern @@ -708,7 +780,7 @@ let createNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com match codec, lm.lg.decodingKind with | Decode, Copy -> // Copy-decoding backend expect all values to be declared even if they are "dummies" - Some ({AcnFuncBodyResult.funcBody = lm.acn.Null_declare pp; errCodes = []; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=Some pp}) + Some ({AcnFuncBodyResult.funcBody = lm.acn.Null_declare pp; errCodes = []; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=Some pp; typeEncodingKind = Some (AcnNullEncodingType None)}) | _ -> None | Some encPattern -> let arrsBits, arrBytes, nBitsSize = @@ -723,12 +795,12 @@ let createNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com let arrsBits = bitStringPattern.ToCharArray() |> Seq.mapi(fun i x -> ((i+1).ToString()) + "=>" + if x='0' then "0" else "1") |> Seq.toList arrsBits,arrBytes,(BigInteger bitStringPattern.Length) let ret = nullType pp arrBytes nBitsSize arrsBits errCode.errCodeName o.acnProperties.savePosition codec - Some ({AcnFuncBodyResult.funcBody = ret; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= lm.lg.acn.null_valIsUnReferenced; bBsIsUnReferenced=false; resultExpr=resultExpr}) + Some ({AcnFuncBodyResult.funcBody = ret; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= lm.lg.acn.null_valIsUnReferenced; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnNullEncodingType (Some encPattern))}) let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let getExternalField0 (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) asn1TypeIdWithDependency func1 = @@ -802,46 +874,48 @@ let getExternalFieldType (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFiel let createStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.StringType) (typeDefinition:TypeDefinitionOrReference) (defOrRef:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (uperFunc: UPerFunction) (us:State) = let Acn_String_Ascii_FixSize = lm.acn.Acn_String_Ascii_FixSize let Acn_String_Ascii_Internal_Field_Determinant = lm.acn.Acn_String_Ascii_Internal_Field_Determinant - let Acn_String_Ascii_Null_Terminated = lm.acn.Acn_String_Ascii_Null_Terminated + let Acn_String_Ascii_Null_Terminated = lm.acn.Acn_String_Ascii_Null_Terminated let Acn_String_Ascii_External_Field_Determinant = lm.acn.Acn_String_Ascii_External_Field_Determinant let Acn_String_CharIndex_External_Field_Determinant = lm.acn.Acn_String_CharIndex_External_Field_Determinant let Acn_IA5String_CharIndex_External_Field_Determinant = lm.acn.Acn_IA5String_CharIndex_External_Field_Determinant - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) (us:State) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) (us:State) = let pp, resultExpr = adaptArgument lm codec p let td = (lm.lg.getStrTypeDefinition o.typeDef).longTypedefName2 lm.lg.hasModules (ToC p.modName) let funcBodyContent, ns = match o.acnEncodingClass with - | Acn_Enc_String_uPER _ -> uperFunc.funcBody_e errCode p |> Option.map(fun x -> x.funcBody, x.errCodes, x.localVariables), us - | Acn_Enc_String_uPER_Ascii _ -> + | Acn_Enc_String_uPER _ -> + uperFunc.funcBody_e errCode nestingScope p |> Option.map(fun x -> x.funcBody, x.errCodes, x.localVariables), us // TODO: Placeholder (uper) ou bien? + | Acn_Enc_String_uPER_Ascii _ -> match o.maxSize.uper = o.minSize.uper with | true -> Some (Acn_String_Ascii_FixSize pp errCode.errCodeName ( o.maxSize.uper) codec, [errCode], []), us | false -> let nSizeInBits = GetNumberOfBitsForNonNegativeInteger ( (o.maxSize.acn - o.minSize.acn)) Some (Acn_String_Ascii_Internal_Field_Determinant pp errCode.errCodeName ( o.maxSize.acn) ( o.minSize.acn) nSizeInBits codec , [errCode], []), us - | Acn_Enc_String_Ascii_Null_Terminated (_,nullChars) -> Some (Acn_String_Ascii_Null_Terminated pp errCode.errCodeName ( o.maxSize.acn) nullChars codec, [errCode], []), us - | Acn_Enc_String_Ascii_External_Field_Determinant _ -> + | Acn_Enc_String_Ascii_Null_Terminated (_,nullChars) -> + Some (Acn_String_Ascii_Null_Terminated pp errCode.errCodeName ( o.maxSize.acn) nullChars codec, [errCode], []), us + | Acn_Enc_String_Ascii_External_Field_Determinant _ -> let extField = getExternalField r deps t.id Some(Acn_String_Ascii_External_Field_Determinant pp errCode.errCodeName ( o.maxSize.acn) extField codec, [errCode], []), us - | Acn_Enc_String_CharIndex_External_Field_Determinant _ -> + | Acn_Enc_String_CharIndex_External_Field_Determinant _ -> let extField = getExternalField r deps t.id - let typeDefinitionName = defOrRef.longTypedefName2 lm.lg.hasModules//getTypeDefinitionName t.id.tasInfo typeDefinition let nBits = GetNumberOfBitsForNonNegativeInteger (BigInteger (o.uperCharSet.Length-1)) let encDecStatement = match o.uperCharSet.Length = 128 with | false -> let arrAsciiCodes = o.uperCharSet |> Array.map(fun x -> BigInteger (System.Convert.ToInt32 x)) Acn_String_CharIndex_External_Field_Determinant pp errCode.errCodeName ( o.maxSize.acn) arrAsciiCodes (BigInteger o.uperCharSet.Length) extField td nBits codec - | true -> Acn_IA5String_CharIndex_External_Field_Determinant pp errCode.errCodeName ( o.maxSize.acn) extField td nBits codec + | true -> Acn_IA5String_CharIndex_External_Field_Determinant pp errCode.errCodeName o.maxSize.acn extField td nBits (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) codec Some(encDecStatement, [errCode], []), us match funcBodyContent with | None -> None, ns - | Some (funcBodyContent,errCodes, localVars) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVars; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}), ns + | Some (funcBodyContent,errCodes, localVars) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVars; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnStringEncodingType o.acnEncodingClass)}), ns let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p us) (fun atc -> true) icd soSparkAnnotations [] us let createAcnStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) (lm:LanguageMacros) (codec:CommonTypes.Codec) (typeId : ReferenceToType) (t:Asn1AcnAst.AcnReferenceToIA5String) (us:State) = @@ -856,7 +930,7 @@ let createAcnStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF let typeDefinitionName = ToC2(r.args.TypePrefix + t.tasName.Value) let o = t.str - let uper_funcBody (errCode:ErrorCode) (p:CallerScope) = + let uper_funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let td = let md = r.GetModuleByName t.modName let tas = md.GetTypeAssignmentByName t.tasName r @@ -893,20 +967,42 @@ let createAcnStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF let arrAsciiCodes = o.uperCharSet |> Array.map(fun x -> BigInteger (System.Convert.ToInt32 x)) InternalItem_string_with_alpha pp errCode.errCodeName td i (BigInteger (o.uperCharSet.Length-1)) arrAsciiCodes (BigInteger (o.uperCharSet.Length)) nBits codec let nSizeInBits = GetNumberOfBitsForNonNegativeInteger ( (o.maxSize.uper - o.minSize.uper)) + let sqfProofGen = { + SequenceOfLikeProofGen.acnOuterMaxSize = nestingScope.acnOuterMaxSize + uperOuterMaxSize = nestingScope.uperOuterMaxSize + nestingLevel = nestingScope.nestingLevel + nestingIx = nestingScope.nestingIx + acnMaxOffset = nestingScope.acnOffset + uperMaxOffset = nestingScope.uperOffset + typeInfo = { + uperMaxSizeBits = o.acnEncodingClass.charSizeInBits + acnMaxSizeBits = o.acnEncodingClass.charSizeInBits + typeKind = Some (AcnStringEncodingType o.acnEncodingClass) + } + sel = pp + ixVariable = i + } + let sqfProofGenRes = lm.lg.generateSequenceOfLikeProof ACN (SequenceOfLike.StrType o) sqfProofGen codec + let preSerde = sqfProofGenRes |> Option.map (fun r -> r.preSerde) + let postSerde = sqfProofGenRes |> Option.map (fun r -> r.postSerde) + let postInc = sqfProofGenRes |> Option.map (fun r -> r.postInc) + let invariant = sqfProofGenRes |> Option.map (fun r -> r.invariant) + let introSnap = nestingScope.nestingLevel = 0 + let funcBodyContent, localVariables = match o.minSize with | _ when o.maxSize.uper < 65536I && o.maxSize.uper=o.minSize.uper -> - str_FixedSize pp typeDefinitionName i internalItem ( o.minSize.uper) nBits nBits 0I initExpr codec, charIndex@nStringLength + str_FixedSize pp typeDefinitionName i internalItem o.minSize.uper nBits nBits 0I initExpr introSnap preSerde postSerde postInc invariant codec, charIndex@nStringLength | _ when o.maxSize.uper < 65536I && o.maxSize.uper<>o.minSize.uper -> - str_VarSize pp typeDefinitionName i internalItem ( o.minSize.uper) ( o.maxSize.uper) nSizeInBits nBits nBits 0I initExpr codec , charIndex@nStringLength + str_VarSize pp typeDefinitionName i internalItem o.minSize.uper o.maxSize.uper nSizeInBits nBits nBits 0I initExpr codec , charIndex@nStringLength | _ -> let funcBodyContent,localVariables = DAstUPer.handleFragmentation lm p codec errCode ii ( o.uperMaxSizeInBits) o.minSize.uper o.maxSize.uper internalItem nBits false true funcBodyContent,charIndex@localVariables - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = lv::localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = lv::localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnStringEncodingType o.acnEncodingClass)} - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let td = (lm.lg.getStrTypeDefinition o.typeDef).longTypedefName2 lm.lg.hasModules (ToC p.modName) let pp, resultExpr = adaptArgument lm codec p let funcBodyContent = @@ -929,14 +1025,15 @@ let createAcnStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF | false -> let arrAsciiCodes = t.str.uperCharSet |> Array.map(fun x -> BigInteger (System.Convert.ToInt32 x)) Acn_String_CharIndex_External_Field_Determinant pp errCode.errCodeName ( t.str.maxSize.acn) arrAsciiCodes (BigInteger t.str.uperCharSet.Length) extField td nBits codec - | true -> Acn_IA5String_CharIndex_External_Field_Determinant pp errCode.errCodeName ( t.str.maxSize.acn) extField td nBits codec + | true -> Acn_IA5String_CharIndex_External_Field_Determinant pp errCode.errCodeName t.str.maxSize.acn extField td nBits (nestingScope.acnOuterMaxSize - nestingScope.acnOffset) codec Some(encDecStatement, [], []) | Acn_Enc_String_uPER _ -> - let x = (uper_funcBody errCode) p + let x = uper_funcBody errCode nestingScope p Some(x.funcBody, x.errCodes, x.localVariables) match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, lvs) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::errCodes |> List.distinct ; localVariables = lvs; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, lvs) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::errCodes |> List.distinct ; localVariables = lvs; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnStringEncodingType o.acnEncodingClass)}) (funcBody errCode), ns @@ -952,7 +1049,7 @@ let createOctetStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInserte let lv = SequenceOfIndex (t.id.SequenceOfLevel + 1, None) let nAlignSize = 0I; let td = typeDefinition.longTypedefName2 lm.lg.hasModules - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = joinedOrAsIdentifier lm codec p let access = lm.lg.getAccess p.arg let funcBodyContent = @@ -1000,19 +1097,20 @@ let createOctetStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInserte match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, localVariables) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, localVariables) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (AcnOctetStringEncodingType o.acnEncodingClass)}) let soSparkAnnotations = Some (sparkAnnotations lm td codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let createBitStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.BitString) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (uperFunc: UPerFunction) (us:State) = let nAlignSize = 0I; let bitString_FixSize = lm.uper.bitString_FixSize let bitString_VarSize = lm.uper.bitString_VarSize let td = typeDefinition.longTypedefName2 lm.lg.hasModules - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = joinedOrAsIdentifier lm codec p let access = lm.lg.getAccess p.arg let funcBodyContent = @@ -1047,12 +1145,13 @@ let createBitStringFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF Some(fncBody, [errCode],nStringLength) match funcBodyContent with | None -> None - | Some (funcBodyContent,errCodes, localVariables) -> Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | Some (funcBodyContent,errCodes, localVariables) -> + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnBitStringEncodingType o.acnEncodingClass)}) let soSparkAnnotations = Some(sparkAnnotations lm td codec) let icdFnc fieldName sPresent comments = [{IcdRow.fieldName = fieldName; comments = comments; sPresent=sPresent;sType=(IcdPlainType (getASN1Name t)); sConstraint=None; minLengthInBits = o.acnMinSizeInBits ;maxLengthInBits=o.acnMaxSizeInBits;sUnits=t.unitsOfMeasure; rowType = IcdRowType.FieldRow; idxOffset = None}] let icd = {IcdArgAux.canBeEmbedded = true; baseAsn1Kind = (getASN1Name t); rowsFunc = icdFnc; commentsForTas=[]; scope="type"; name= None} - createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.SequenceOf) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (child:Asn1Type) (us:State) = let oct_sqf_null_terminated = lm.acn.oct_sqf_null_terminated @@ -1074,46 +1173,77 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInserted let nAlignSize = 0I; let nIntItemMaxSize = child.acnMaxSizeInBits let td = typeDefinition.longTypedefName2 lm.lg.hasModules - let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = joinedOrAsIdentifier lm codec p // `childInitExpr` is used to initialize the array of elements in which we will write their decoded values // It is only meaningful for "Copy" decoding kind, since InPlace will directly modify `p`'s array let childInitExpr = DAstInitialize.getChildExpression lm child let access = lm.lg.getAccess p.arg match child.getAcnFunction codec with - | None -> None, us + | None -> None, us | Some chFunc -> - let internalItem, ns = chFunc.funcBody us acnArgs ({p with arg = lm.lg.getArrayItem p.arg i child.isIA5String}) + let childNestingScope = {nestingScope with nestingLevel = nestingScope.nestingLevel + 1} + let internalItem, ns = chFunc.funcBody us acnArgs childNestingScope ({p with arg = lm.lg.getArrayItem p.arg i child.isIA5String}) + + let sqfProofGen = { + SequenceOfLikeProofGen.acnOuterMaxSize = nestingScope.acnOuterMaxSize + uperOuterMaxSize = nestingScope.uperOuterMaxSize + nestingLevel = nestingScope.nestingLevel + nestingIx = nestingScope.nestingIx + acnMaxOffset = nestingScope.acnOffset + uperMaxOffset = nestingScope.uperOffset + typeInfo = { + uperMaxSizeBits = child.uperMaxSizeInBits + acnMaxSizeBits = child.acnMaxSizeInBits + typeKind = internalItem |> Option.bind (fun i -> i.typeEncodingKind) + } + sel = pp + ixVariable = i + } + let sqfProofGenRes = lm.lg.generateSequenceOfLikeProof ACN (SqOf o) sqfProofGen codec + let preSerde = sqfProofGenRes |> Option.map (fun r -> r.preSerde) + let postSerde = sqfProofGenRes |> Option.map (fun r -> r.postSerde) + let postInc = sqfProofGenRes |> Option.map (fun r -> r.postInc) + let invariant = sqfProofGenRes |> Option.map (fun r -> r.invariant) + let ret = match o.acnEncodingClass with | SZ_EC_FIXED_SIZE | SZ_EC_LENGTH_EMBEDDED _ -> - let nSizeInBits = GetNumberOfBitsForNonNegativeInteger ( (o.maxSize.acn - o.minSize.acn)) + let nSizeInBits = GetNumberOfBitsForNonNegativeInteger (o.maxSize.acn - o.minSize.acn) let nStringLength = match o.minSize.uper = o.maxSize.uper, codec with | true , _ -> [] | false, Encode -> [] | false, Decode -> [lm.lg.uper.count_var] + let absOffset = nestingScope.acnOffset + let remBits = nestingScope.acnOuterMaxSize - nestingScope.acnOffset + let lvl = bigint (max 0 (nestingScope.nestingLevel - 1)) + let ix = bigint nestingScope.nestingIx + 1I + let offset = nestingScope.acnRelativeOffset + let introSnap = nestingScope.nestingLevel = 0 + match internalItem with - | None -> + | None -> match o.isFixedSize with | true -> None | false -> - let funcBody = varSize pp access td i "" o.minSize.acn o.maxSize.acn nSizeInBits child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName codec - Some ({AcnFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = lv@nStringLength; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + let funcBody = varSize pp access td i "" o.minSize.acn o.maxSize.acn nSizeInBits child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName absOffset remBits lvl ix offset introSnap preSerde postSerde postInc invariant codec + Some ({AcnFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = lv@nStringLength; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=None}) | Some internalItem -> let childErrCodes = internalItem.errCodes let ret, localVariables = match o.isFixedSize with - | true -> fixedSize pp td i internalItem.funcBody o.minSize.acn child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr codec, nStringLength - | false -> varSize pp access td i internalItem.funcBody o.minSize.acn o.maxSize.acn nSizeInBits child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName codec, nStringLength - Some ({AcnFuncBodyResult.funcBody = ret; errCodes = errCode::childErrCodes; localVariables = lv@(internalItem.localVariables@localVariables); bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + | true -> fixedSize pp td i internalItem.funcBody o.minSize.acn child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr codec, nStringLength + | false -> varSize pp access td i internalItem.funcBody o.minSize.acn o.maxSize.acn nSizeInBits child.acnMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName absOffset remBits lvl ix offset introSnap preSerde postSerde postInc invariant codec, nStringLength + let typeEncodingKind = internalItem.typeEncodingKind |> Option.map (fun tpe -> TypeEncodingKind.SequenceOfEncodingType (tpe, o.acnEncodingClass)) + Some ({AcnFuncBodyResult.funcBody = ret; errCodes = errCode::childErrCodes; localVariables = lv@(internalItem.localVariables@localVariables); bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) - | SZ_EC_ExternalField _ -> + | SZ_EC_ExternalField _ -> match internalItem with - | None -> None + | None -> None | Some internalItem -> let localVariables = internalItem.localVariables let childErrCodes = internalItem.errCodes @@ -1131,14 +1261,16 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInserted assert internalItem.resultExpr.IsSome internalItemBody + "\n" + (lm.uper.update_array_item pp i internalItem.resultExpr.Value) | _ -> internalItemBody + let introSnap = nestingScope.nestingLevel = 0 let funcBodyContent = match o.isFixedSize with - | true -> oct_sqf_external_field_fix_size td pp access i internalItemBody (if o.minSize.acn=0I then None else Some o.minSize.acn) o.maxSize.acn extField unsigned nAlignSize errCode.errCodeName o.child.acnMinSizeInBits o.child.acnMaxSizeInBits childInitExpr codec - | false -> external_field td pp access i internalItemBody (if o.minSize.acn=0I then None else Some o.minSize.acn) o.maxSize.acn extField unsigned nAlignSize errCode.errCodeName o.child.acnMinSizeInBits o.child.acnMaxSizeInBits childInitExpr codec - Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::childErrCodes; localVariables = lv@localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) - | SZ_EC_TerminationPattern bitPattern -> + | true -> oct_sqf_external_field_fix_size td pp access i internalItemBody (if o.minSize.acn=0I then None else Some o.minSize.acn) o.maxSize.acn extField unsigned nAlignSize errCode.errCodeName o.child.acnMinSizeInBits o.child.acnMaxSizeInBits childInitExpr introSnap preSerde postSerde postInc invariant codec + | false -> external_field td pp access i internalItemBody (if o.minSize.acn=0I then None else Some o.minSize.acn) o.maxSize.acn extField unsigned nAlignSize errCode.errCodeName o.child.acnMinSizeInBits o.child.acnMaxSizeInBits childInitExpr introSnap preSerde postSerde postInc invariant codec + let typeEncodingKind = internalItem.typeEncodingKind |> Option.map (fun tpe -> TypeEncodingKind.SequenceOfEncodingType (tpe, o.acnEncodingClass)) + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::childErrCodes; localVariables = lv@localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) + | SZ_EC_TerminationPattern bitPattern -> match internalItem with - | None -> None + | None -> None | Some internalItem -> let mod8 = bitPattern.Value.Length % 8 let suffix = [1 .. mod8] |> Seq.map(fun _ -> "0") |> Seq.StrJoin "" @@ -1158,10 +1290,11 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInserted let lv2 = match codec, lm.lg.acn.checkBitPatternPresentResult with - | Decode, true -> [IntegerLocalVariable ("checkBitPatternPresentResult", Some (lm.lg.intValueToString 0I (ASN1SCC_Int8 (-128I, 127I))))] - | _ -> [] + | Decode, true -> [IntegerLocalVariable ("checkBitPatternPresentResult", Some (lm.lg.intValueToString 0I (ASN1SCC_Int8 (-128I, 127I))))] + | _ -> [] - Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::childErrCodes; localVariables = lv2@lv@localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=None}) + let typeEncodingKind = internalItem.typeEncodingKind |> Option.map (fun tpe -> TypeEncodingKind.SequenceOfEncodingType (tpe, o.acnEncodingClass)) + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCode::childErrCodes; localVariables = lv2@lv@localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=None; typeEncodingKind=typeEncodingKind}) ret,ns let soSparkAnnotations = Some(sparkAnnotations lm td codec) @@ -1230,12 +1363,12 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn match prmUpdateStatement with | None -> None, ns1 | Some prmUpdateStatement -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = - prmUpdateStatement.updateAcnChildFnc child vTarget pSrcRoot + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + prmUpdateStatement.updateAcnChildFnc child nestingScope vTarget pSrcRoot Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=prmUpdateStatement.errCodes; testCaseFnc = prmUpdateStatement.testCaseFnc; localVariables=[]}), ns1 | AcnDepSizeDeterminant (minSize, maxSize, szAcnProp) -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let pSizeable, checkPath = getAccessFromScopeNodeList d.asn1Type false lm pSrcRoot let unsigned = @@ -1269,19 +1402,19 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn let errCodes0, localVariables0, ns = match asn1TypeD.acnEncFunction with | Some f -> - let fncBdRes, ns = f.funcBody us [] {CallerScope.modName = ""; arg = Selection.valueEmptyPath "dummy"} + let fncBdRes, ns = f.funcBody us [] (NestingScope.init asn1TypeD.acnMaxSizeInBits asn1TypeD.uperMaxSizeInBits) {CallerScope.modName = ""; arg = Selection.valueEmptyPath "dummy"} match fncBdRes with | Some x -> x.errCodes, x.localVariables, ns | None -> [], [], us | None -> [], [], us - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let pSizeable, checkPath = getAccessFromScopeNodeList d.asn1Type false lm pSrcRoot let sComment= match asn1TypeD.acnEncFunction with | Some f -> - let fncBdRes, _ = f.funcBody us [] pSizeable + let fncBdRes, _ = f.funcBody us [] nestingScope pSizeable match fncBdRes with | None -> "" | Some a -> a.funcBody @@ -1298,7 +1431,7 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=errCodes0; testCaseFnc=testCaseFnc; localVariables= localVariables0@localVars}), ns | AcnDepIA5StringSizeDeterminant (minSize, maxSize, szAcnProp) -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let pSizeable, checkPath = getAccessFromScopeNodeList d.asn1Type true lm pSrcRoot let updateStatement = sizeDependency v (getStringSize (pSizeable.arg.joined lm.lg)) minSize.uper maxSize.uper true child.typeDefinitionBodyWithinSeq @@ -1309,7 +1442,7 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn atc.testCaseTypeIDsMap.TryFind d.asn1Type Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=[]; testCaseFnc=testCaseFnc; localVariables=[]}), us | AcnDepPresenceBool -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let parDecTypeSeq = match d.asn1Type with @@ -1325,7 +1458,7 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn | None -> Some TcvComponentAbsent Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=[]; testCaseFnc=testCaseFnc; localVariables=[]}), us | AcnDepPresence (relPath, chc) -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let choicePath, checkPath = getAccessFromScopeNodeList d.asn1Type false lm pSrcRoot let arrsChildUpdates = @@ -1359,7 +1492,7 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn | _ -> None Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=[] ; testCaseFnc=testCaseFnc; localVariables=[]}), us | AcnDepPresenceStr (relPath, chc, str) -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let choicePath, checkPath = getAccessFromScopeNodeList d.asn1Type false lm pSrcRoot let arrsChildUpdates = @@ -1391,8 +1524,8 @@ let rec handleSingleUpdateDependency (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.Acn | v1::[] -> Some v1 | _ -> None Some ({AcnChildUpdateResult.updateAcnChildFnc = updateFunc; errCodes=[]; testCaseFnc = testCaseFnc; localVariables=[]}), us - | AcnDepChoiceDeterminant (enm, chc, isOptional) -> - let updateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + | AcnDepChoiceDeterminant (enm, chc, isOptional) -> + let updateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let choicePath, checkPath = getAccessFromScopeNodeList d.asn1Type false lm pSrcRoot let arrsChildUpdates = @@ -1452,7 +1585,7 @@ and getUpdateFunctionUsedInEncoding (r: Asn1AcnAst.AstRoot) (deps: Asn1AcnAst.Ac updates@[f1], nns) ([],us) let restErrCodes = localUpdateFuns |> List.choose id |> List.collect(fun z -> z.errCodes) let restLocalVariables = localUpdateFuns |> List.choose id |> List.collect(fun z -> z.localVariables) - let multiUpdateFunc (child: AcnChild) (vTarget : CallerScope) (pSrcRoot : CallerScope) = + let multiUpdateFunc (child: AcnChild) (nestingScope: NestingScope) (vTarget : CallerScope) (pSrcRoot : CallerScope) = let v = lm.lg.getValue vTarget.arg let arrsLocalUpdateStatements = localUpdateFuns |> @@ -1461,7 +1594,7 @@ and getUpdateFunctionUsedInEncoding (r: Asn1AcnAst.AstRoot) (deps: Asn1AcnAst.Ac let lv = {CallerScope.modName = vTarget.modName; arg = Selection.valueEmptyPath c_name} match fn with | None -> None - | Some fn -> Some(fn.updateAcnChildFnc child lv pSrcRoot)) |> + | Some fn -> Some(fn.updateAcnChildFnc child nestingScope lv pSrcRoot)) |> // TODO: nestingScope? List.choose id let isAlwaysInit (d: AcnDependency): bool = @@ -1528,11 +1661,21 @@ type private SequenceChildStmt = { lvs: LocalVariable list errCodes: ErrorCode list } +type private SequenceChildState = { + us: State + childIx: int + uperAccBits: BigInteger + acnAccBits: BigInteger +} type private SequenceChildResult = { stmts: SequenceChildStmt list resultExpr: string option existVar: string option -} + props: SequenceChildProps + typeKindEncoding: TypeEncodingKind option +} with + member this.joinedBodies (lm:LanguageMacros) (codec:CommonTypes.Codec): string option = + this.stmts |> List.choose (fun s -> s.body) |> nestChildItems lm codec let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFieldDependencies) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Sequence) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (children:SeqChildInfo list) (acnPrms:DastAcnParameter list) (us:State) = (* @@ -1620,7 +1763,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi let acnChildren = children |> List.choose(fun x -> match x with AcnChild z -> Some z | Asn1Child _ -> None) let asn1Children = children |> List.choose(fun x -> match x with Asn1Child z -> Some z | AcnChild _ -> None) - let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let acnlocalVariablesCh = acnChildren |> List.filter(fun x -> match x.Type with Asn1AcnAst.AcnNullType _ -> false | _ -> true) |> @@ -1646,15 +1789,13 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi let printPresenceBit (child:Asn1Child) (existVar: string option)= match child.Optionality with - | None -> None - | Some Asn1AcnAst.AlwaysAbsent -> None - | Some Asn1AcnAst.AlwaysPresent -> None | Some (Asn1AcnAst.Optional opt) -> match opt.acnPresentWhen with - | None -> + | None -> assert (codec = Encode || existVar.IsSome) Some (sequence_presence_optChild (p.arg.joined lm.lg) (lm.lg.getAccess p.arg) (lm.lg.getAsn1ChildBackendName child) existVar errCode.errCodeName codec) - | Some _ -> None + | Some _ -> None + | _ -> None let localVariables = acnlocalVariables let td = lm.lg.getSequenceTypeDefinition o.typeDef @@ -1693,27 +1834,37 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi | _ -> localVariables, None, None, None - let handleChild (us:State) (child:SeqChildInfo): SequenceChildResult * State = + let handleChild (s: SequenceChildState) (child: SeqChildInfo): SequenceChildResult * SequenceChildState = + // This binding is suspect, isn't it + let us = s.us let soSaveBitStrmPosStatement = None + let childNestingScope = + {nestingScope with + nestingLevel = nestingScope.nestingLevel + 1 + nestingIx = nestingScope.nestingIx + s.childIx + uperRelativeOffset = s.uperAccBits + uperOffset = nestingScope.uperOffset + s.uperAccBits + acnRelativeOffset = s.acnAccBits + acnOffset = nestingScope.acnOffset + s.acnAccBits} + match child with | Asn1Child child -> let childTypeDef = child.Type.typeDefinitionOrReference.longTypedefName2 lm.lg.hasModules let childName = lm.lg.getAsn1ChildBackendName child let chFunc = child.Type.getAcnFunction codec + let childSel = lm.lg.getSeqChild p.arg childName child.Type.isIA5String child.Optionality.IsSome + let childP = + let newArg = if lm.lg.usesWrappedOptional && childSel.isOptional && codec = Encode then childSel.asLast else childSel + {p with arg = newArg} let childContentResult, ns1 = match chFunc with - | Some chFunc -> - let newArg = lm.lg.getSeqChild p.arg childName child.Type.isIA5String child.Optionality.IsSome - let newArg = if lm.lg.usesWrappedOptional && newArg.isOptional && codec = Encode then newArg.asLast else newArg - let newP = {p with arg = newArg} - chFunc.funcBodyAsSeqComp us [] newP childName + | Some chFunc -> chFunc.funcBodyAsSeqComp us [] childNestingScope childP childName | None -> None, us - //handle present-when acn property let present_when_statements, existVar, ns2 = let acnPresenceStatement, lvs, errCodes, existVar, ns1b = match child.Optionality with - | Some (Asn1AcnAst.Optional opt) -> + | Some (Asn1AcnAst.Optional opt) -> match opt.acnPresentWhen with | None -> match codec with @@ -1724,7 +1875,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi let existVar = ToC (child._c_name + "_exist") let lv = FlagLocalVariable (existVar, None) None, [lv], [], Some existVar, ns1 - | Some (PresenceWhenBool _) -> + | Some (PresenceWhenBool _) -> match codec with | Encode -> None, [], [], None, ns1 | Decode -> @@ -1750,7 +1901,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi | _ -> None, [], [], None, ns1 {acnStatement=AcnPresenceStatement; body=acnPresenceStatement; lvs=lvs; errCodes=errCodes}, existVar, ns1b - let childEncDecStatement, childResultExpr, ns3 = + let childEncDecStatement, childResultExpr, childTpeKind, ns3 = match childContentResult with | None -> // Copy-decoding expects to have a result expression (even if unused), so we pick the initExpression @@ -1761,8 +1912,8 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi match child.Optionality with | Some Asn1AcnAst.AlwaysPresent -> let childBody = Some(sequence_always_present_child (p.arg.joined lm.lg) (lm.lg.getAccess p.arg) childName None childResultExpr soSaveBitStrmPosStatement codec) - Some {acnStatement=Asn1ChildEncodeStatement; body=childBody; lvs=[]; errCodes=[]}, childResultExpr, ns2 - | _ -> None, childResultExpr, ns2 + Some {acnStatement=Asn1ChildEncodeStatement; body=childBody; lvs=[]; errCodes=[]}, childResultExpr, None, ns2 + | _ -> None, childResultExpr, None, ns2 | Some childContent -> let childBody, chLocalVars = match child.Optionality with @@ -1776,13 +1927,20 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi | None -> Some(sequence_optional_child pp (lm.lg.getAccess p.arg) childName childContent.funcBody existVar childContent.resultExpr childTypeDef soSaveBitStrmPosStatement codec), childContent.localVariables | Some v -> - let defInit= child.Type.initFunction.initByAsn1Value ({p with arg = lm.lg.getSeqChild p.arg childName child.Type.isIA5String child.Optionality.IsSome}) (mapValue v).kind + let defInit= child.Type.initFunction.initByAsn1Value childP (mapValue v).kind Some(sequence_default_child pp (lm.lg.getAccess p.arg) childName childContent.funcBody defInit existVar childContent.resultExpr childTypeDef soSaveBitStrmPosStatement codec), childContent.localVariables - Some {acnStatement=Asn1ChildEncodeStatement; body=childBody; lvs=chLocalVars; errCodes=childContent.errCodes}, childContent.resultExpr, ns2 - {stmts=[present_when_statements]@(childEncDecStatement |> Option.toList); resultExpr=childResultExpr; existVar=existVar}, ns3 - | AcnChild acnChild -> + Some {acnStatement=Asn1ChildEncodeStatement; body=childBody; lvs=chLocalVars; errCodes=childContent.errCodes}, childContent.resultExpr, childContent.typeEncodingKind, ns2 + let stmts = [present_when_statements]@(childEncDecStatement |> Option.toList) + let tpeKind = + if child.Optionality.IsSome then childTpeKind |> Option.map OptionEncodingType + else childTpeKind + let typeInfo = {uperMaxSizeBits=child.uperMaxSizeInBits; acnMaxSizeBits=child.acnMaxSizeInBits; typeKind=tpeKind} + let props = {sel=Some (childSel.joined lm.lg); uperMaxOffset=s.uperAccBits; acnMaxOffset=s.acnAccBits; typeInfo=typeInfo} + let res = {stmts=stmts; resultExpr=childResultExpr; existVar=existVar; props=props; typeKindEncoding=tpeKind} + let newAcc = {us=ns3; childIx=s.childIx + 1; uperAccBits=s.uperAccBits + child.uperMaxSizeInBits; acnAccBits=s.acnAccBits + child.acnMaxSizeInBits} + res, newAcc + | AcnChild acnChild -> //handle updates - //acnChild.c_name let childP = {CallerScope.modName = p.modName; arg= Selection.valueEmptyPath (getAcnDeterminantName acnChild.id)} let updateStatement, ns1 = @@ -1791,61 +1949,81 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi let pRoot : CallerScope = lm.lg.getParamType t codec //???? let updateStatement, lvs, errCodes = match acnChild.funcUpdateStatement with - | Some funcUpdateStatement -> Some (funcUpdateStatement.updateAcnChildFnc acnChild childP pRoot), funcUpdateStatement.localVariables, funcUpdateStatement.errCodes + | Some funcUpdateStatement -> Some (funcUpdateStatement.updateAcnChildFnc acnChild childNestingScope childP pRoot), funcUpdateStatement.localVariables, funcUpdateStatement.errCodes | None -> None, [], [] Some {acnStatement=AcnChildUpdateStatement; body=updateStatement; lvs=lvs; errCodes=errCodes}, us | Decode -> None, us //acn child encode/decode - let childEncDecStatement, ns2 = + let childEncDecStatement, childTpeKind, ns2 = let chFunc = acnChild.funcBody codec - let childContentResult = chFunc [] childP + let childContentResult = chFunc [] childNestingScope childP match childContentResult with - | None -> None, ns1 + | None -> None, None, ns1 | Some childContent -> match codec with | Encode -> match acnChild.Type with | Asn1AcnAst.AcnNullType _ -> let childBody = Some (sequence_mandatory_child acnChild.c_name childContent.funcBody soSaveBitStrmPosStatement codec) - Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=childContent.errCodes}, ns1 + Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=childContent.errCodes}, childContent.typeEncodingKind, ns1 | _ -> let _errCodeName = ToC ("ERR_ACN" + (codec.suffix.ToUpper()) + "_" + ((acnChild.id.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm")) + "_UNINITIALIZED") let errCode, ns1a = getNextValidErrorCode ns1 _errCodeName None let childBody = Some (sequence_acn_child acnChild.c_name childContent.funcBody errCode.errCodeName soSaveBitStrmPosStatement codec) - Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=errCode::childContent.errCodes}, ns1a + Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=errCode::childContent.errCodes}, childContent.typeEncodingKind, ns1a | Decode -> let childBody = Some (sequence_mandatory_child acnChild.c_name childContent.funcBody soSaveBitStrmPosStatement codec) - Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=childContent.errCodes}, ns1 - {stmts=(updateStatement |> Option.toList)@(childEncDecStatement |> Option.toList); resultExpr=None; existVar=None}, ns2 - + Some {acnStatement=AcnChildEncodeStatement; body=childBody; lvs=childContent.localVariables; errCodes=childContent.errCodes}, childContent.typeEncodingKind, ns1 + let stmts = (updateStatement |> Option.toList)@(childEncDecStatement |> Option.toList) + // Note: uperMaxSizeBits and uperAccBits here do not make sense since we are in ACN + let typeInfo = {uperMaxSizeBits=0I; acnMaxSizeBits=child.acnMaxSizeInBits; typeKind=childTpeKind} + let props = {sel=Some (childP.arg.joined lm.lg); uperMaxOffset=s.uperAccBits; acnMaxOffset=s.acnAccBits; typeInfo=typeInfo} + let res = {stmts=stmts; resultExpr=None; existVar=None; props=props; typeKindEncoding=childTpeKind} + let newAcc = {us=ns2; childIx=s.childIx + 1; uperAccBits=s.uperAccBits; acnAccBits=s.acnAccBits + acnChild.Type.acnMaxSizeInBits} + res, newAcc // find acn inserted fields, which are not NULL types and which have no dependency. // For those fields we should generated no anc encode/decode function // Otherwise, the encoding function is wrong since an uninitialized value is encoded. let existsAcnChildWithNoUpdates = acnChildren |> - List.filter (fun acnChild -> match acnChild.Type with Asn1AcnAst.AcnNullType _ -> false | _ -> true) |> - List.filter(fun acnChild -> - let childP = {CallerScope.modName = p.modName; arg = Selection.valueEmptyPath (getAcnDeterminantName acnChild.id)} - let pRoot : CallerScope = lm.lg.getParamType t codec - let updateStatement = - match acnChild.funcUpdateStatement with - | Some funcUpdateStatement -> Some (funcUpdateStatement.updateAcnChildFnc acnChild childP pRoot) - | None -> None - updateStatement.IsNone) + List.filter (fun acnChild -> match acnChild.Type with Asn1AcnAst.AcnNullType _ -> false | _ -> acnChild.funcUpdateStatement.IsNone) let saveInitialBitStrmStatements = soSaveInitialBitStrmStatement |> Option.toList - let childrenStatements00, ns = children |> foldMap handleChild us + let nbPresenceBits = asn1Children |> List.sumBy (fun c -> + match c.Optionality with + | Some (Optional opt) -> if opt.acnPresentWhen.IsNone then 1I else 0I + | _ -> 0I + ) + let childrenStatements00, scs = children |> foldMap handleChild {us=us; childIx=0; uperAccBits=nbPresenceBits; acnAccBits=nbPresenceBits} + let ns = scs.us let childrenStatements0 = childrenStatements00 |> List.collect (fun xs -> xs.stmts) - let childrenStatements = childrenStatements0 |> List.choose(fun s -> s.body) + let presenceBits = ((List.zip children childrenStatements00) |> List.choose (fun (child, res) -> match child with | Asn1Child asn1 -> printPresenceBit asn1 res.existVar | AcnChild _ -> None)) + let seqProofGen = + let presenceBitsInfo = presenceBits |> List.mapi (fun i _ -> + {sel=None; uperMaxOffset = bigint i; acnMaxOffset = bigint i; + typeInfo = {uperMaxSizeBits = 1I; acnMaxSizeBits = 1I; typeKind = Some (AcnBooleanEncodingType None)};}) + let children = childrenStatements00 |> List.map (fun xs -> xs.props) + {acnOuterMaxSize = nestingScope.acnOuterMaxSize; uperOuterMaxSize = nestingScope.uperOuterMaxSize; + nestingLevel = nestingScope.nestingLevel; nestingIx = nestingScope.nestingIx; + uperMaxOffset = nestingScope.uperOffset; acnMaxOffset = nestingScope.acnOffset; + acnSiblingMaxSize = nestingScope.acnSiblingMaxSize; uperSiblingMaxSize = nestingScope.uperSiblingMaxSize; + children = presenceBitsInfo @ children} + let allStmts = + let presenceBits = presenceBits |> List.map Some + let children = childrenStatements00 |> List.map (fun s -> s.joinedBodies lm codec) + presenceBits @ children + let childrenStatements = lm.lg.generateSequenceChildProof ACN allStmts seqProofGen codec + let childrenLocalvars = childrenStatements0 |> List.collect(fun s -> s.lvs) let childrenExistVar = childrenStatements00 |> List.choose(fun res -> res.existVar) let childrenResultExpr = childrenStatements00 |> List.choose(fun res -> res.resultExpr) let childrenErrCodes = childrenStatements0 |> List.collect(fun s -> s.errCodes) + let childrenTypeKindEncoding = childrenStatements00 |> List.map (fun s -> s.typeKindEncoding) let resultExpr, seqBuild= match codec, lm.lg.decodingKind with @@ -1863,7 +2041,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi Some resultExpr, [lm.uper.sequence_build resultExpr (typeDefinition.longTypedefName2 lm.lg.hasModules) (existSeq@childrenResultExpr)] | _ -> None, [] - let seqContent = (saveInitialBitStrmStatements@presenceBits@childrenStatements@(post_encoding_function |> Option.toList)@seqBuild) |> nestChildItems lm codec + let seqContent = (saveInitialBitStrmStatements@childrenStatements@(post_encoding_function |> Option.toList)@seqBuild) |> nestChildItems lm codec match existsAcnChildWithNoUpdates with | [] -> match seqContent with @@ -1874,9 +2052,9 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi match lm.lg.decodeEmptySeq (p.arg.joined lm.lg) with | None -> None, ns | Some decodeEmptySeq -> - Some ({AcnFuncBodyResult.funcBody = decodeEmptySeq; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=true; resultExpr=Some decodeEmptySeq}), ns + Some ({AcnFuncBodyResult.funcBody = decodeEmptySeq; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=true; resultExpr=Some decodeEmptySeq; typeEncodingKind=Some (SequenceEncodingType childrenTypeKindEncoding)}), ns | Some ret -> - Some ({AcnFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=(o.acnMaxSizeInBits = 0I); resultExpr=resultExpr}), ns + Some ({AcnFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=(o.acnMaxSizeInBits = 0I); resultExpr=resultExpr; typeEncodingKind=Some (SequenceEncodingType childrenTypeKindEncoding)}), ns | errChild::_ -> let determinantUsage = @@ -2000,20 +2178,23 @@ let createChoiceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFiel let typeDefinitionName = defOrRef.longTypedefName2 lm.lg.hasModules//getTypeDefinitionName t.id.tasInfo typeDefinition - let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let td = (lm.lg.getChoiceTypeDefinition o.typeDef).longTypedefName2 lm.lg.hasModules (ToC p.modName) + let acnSiblingMaxSize = children |> List.map (fun c -> c.chType.acnMaxSizeInBits) |> List.max + let uperSiblingMaxSize = children |> List.map (fun c -> c.chType.uperMaxSizeInBits) |> List.max let handleChild (us:State) (idx:int) (child:ChChildInfo) = let chFunc = child.chType.getAcnFunction codec let sChildInitExpr = child.chType.initFunction.initExpression - + let childNestingScope = {nestingScope with nestingLevel = nestingScope.nestingLevel + 1; uperSiblingMaxSize = Some uperSiblingMaxSize; acnSiblingMaxSize = Some acnSiblingMaxSize} let childContentResult, ns1 = match chFunc with - | Some chFunc -> - match lm.lg.acn.choice_requires_tmp_decoding with - | false -> chFunc.funcBody us [] ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) - | true when codec = CommonTypes.Decode -> chFunc.funcBody us [] ({CallerScope.modName = p.modName; arg = Selection.valueEmptyPath ((lm.lg.getAsn1ChChildBackendName child) + "_tmp")}) - | true -> chFunc.funcBody us [] ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) - | None -> None, us + | Some chFunc -> + let childP = + if lm.lg.acn.choice_requires_tmp_decoding && codec = Decode then + {CallerScope.modName = p.modName; arg = Selection.valueEmptyPath ((lm.lg.getAsn1ChChildBackendName child) + "_tmp")} + else {p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String} + chFunc.funcBody us [] childNestingScope childP + | None -> None, us let childContent_funcBody, childContent_localVariables, childContent_errCodes = match childContentResult with @@ -2088,13 +2269,14 @@ let createChoiceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFiel let conds = child.acnPresentWhenConditions |>List.map handPresenceCond let pp, _ = joinedOrAsIdentifier lm codec p Some (choiceChild_preWhen pp (lm.lg.getAccess p.arg) (lm.lg.presentWhenName (Some defOrRef) child) childContent_funcBody conds (idx=0) sChildName sChildTypeDef sChoiceTypeName sChildInitExpr codec) - [(childBody, childContent_localVariables, childContent_errCodes)], ns1 + [(childBody, childContent_localVariables, childContent_errCodes, childContentResult |> Option.bind (fun ch -> ch.typeEncodingKind))], ns1 let childrenStatements00, ns = children |> List.mapi (fun i x -> i,x) |> foldMap (fun us (i,x) -> handleChild us i x) us let childrenStatements0 = childrenStatements00 |> List.collect id - let childrenStatements = childrenStatements0 |> List.choose(fun (s,_,_) -> s) - let childrenLocalvars = childrenStatements0 |> List.collect(fun (_,s,_) -> s) - let childrenErrCodes = childrenStatements0 |> List.collect(fun (_,_,s) -> s) + let childrenStatements = childrenStatements0 |> List.choose(fun (s,_,_,_) -> s) + let childrenLocalvars = childrenStatements0 |> List.collect(fun (_,s,_,_) -> s) + let childrenErrCodes = childrenStatements0 |> List.collect(fun (_,_,s,_) -> s) + let childrenTypeKindEncoding = childrenStatements0 |> List.map(fun (_,_,_,s) -> s) let choiceContent, resultExpr = let pp, resultExpr = joinedOrAsIdentifier lm codec p @@ -2106,7 +2288,7 @@ let createChoiceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFiel let extField = getExternalField r deps t.id choice_Enum pp access childrenStatements extField errCode.errCodeName codec, resultExpr | CEC_presWhen -> choice_preWhen pp access childrenStatements errCode.errCodeName codec, resultExpr - Some ({AcnFuncBodyResult.funcBody = choiceContent; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}), ns + Some ({AcnFuncBodyResult.funcBody = choiceContent; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind = Some (ChoiceEncodingType childrenTypeKindEncoding)}), ns let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) @@ -2210,6 +2392,7 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF | None -> match o.hasExtraConstrainsOrChildrenOrAcnArgs with | true -> + // TODO: this is where stuff gets inlined match codec with | Codec.Encode -> baseType.getAcnFunction codec, us | Codec.Decode -> @@ -2219,13 +2402,13 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF match baseTypeAcnFunction with | None -> None | Some baseTypeAcnFunction -> - let funcBody us (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = - baseTypeAcnFunction.funcBody us (acnArgs@paramsArgsPairs) p + let funcBody us (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = + baseTypeAcnFunction.funcBody us (acnArgs@paramsArgsPairs) nestingScope p Some {baseTypeAcnFunction with funcBody = funcBody} ret, us | false -> - let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (us:State) (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = let str = lm.lg.getParamValue t p.arg codec match codec, lm.lg.decodingKind with @@ -2234,11 +2417,11 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF toc, Some toc | _ -> str, None let funcBodyContent = callBaseTypeFunc lm pp baseFncName codec - Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}), us + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (ReferenceEncodingType baseTypeDefinitionName)}), us let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) - let a, ns = createAcnFunction r lm codec t typeDefinition isValidFunc funcBody (fun atc -> true) icd soSparkAnnotations [] us + let a, ns = createAcnFunction r lm codec t typeDefinition isValidFunc funcBody (fun atc -> true) icd soSparkAnnotations [] us Some a, ns | Some encOptions -> @@ -2254,7 +2437,7 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF let baseTypeAcnFunction = baseType.getAcnFunction codec - let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (acnArgs: (AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = let str = lm.lg.getParamValue t p.arg codec match codec, lm.lg.decodingKind with @@ -2274,7 +2457,7 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF match baseTypeAcnFunction with | None -> None, [], [] | Some baseTypeAcnFunction -> - let acnRes, ns = baseTypeAcnFunction.funcBody us (acnArgs) p + let acnRes, ns = baseTypeAcnFunction.funcBody us acnArgs nestingScope p match acnRes with | None -> None, [], [] | Some r -> Some r.funcBody, r.errCodes, r.localVariables @@ -2304,9 +2487,8 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedF let fncBody = bit_string_containing_func pp baseFncName sReqBytesForUperEncoding sReqBitForUperEncoding nBits encOptions.minSize.acn encOptions.maxSize.acn false codec fncBody, [errCode],[] | SZ_EC_TerminationPattern nullVal , _ -> raise(SemanticError (loc, "Invalid type for parameter4")) - - Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + Some ({AcnFuncBodyResult.funcBody = funcBodyContent; errCodes = errCodes; localVariables = localVariables; bValIsUnReferenced= false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (ReferenceEncodingType baseTypeDefinitionName)}) let soSparkAnnotations = Some(sparkAnnotations lm (typeDefinition.longTypedefName2 lm.lg.hasModules) codec) - let a,b = createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs p -> funcBody e acnArgs p, us) (fun atc -> true) icd soSparkAnnotations [] us + let a,b = createAcnFunction r lm codec t typeDefinition isValidFunc (fun us e acnArgs nestingScope p -> funcBody e acnArgs nestingScope p, us) (fun atc -> true) icd soSparkAnnotations [] us Some a, b diff --git a/BackendAst/DAstConstruction.fs b/BackendAst/DAstConstruction.fs index 34436d18c..21b28997b 100644 --- a/BackendAst/DAstConstruction.fs +++ b/BackendAst/DAstConstruction.fs @@ -63,12 +63,12 @@ let private createAcnChild (r:Asn1AcnAst.AstRoot) (deps:Asn1AcnAst.AcnInsertedFi let funcUpdateStatement, ns3 = DAstACN.getUpdateFunctionUsedInEncoding r deps lm m ch.id ns2 let c_name = DAstACN.getAcnDeterminantName ch.id - let newFuncBody (codec:Codec) (prms:((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list)) (p:CallerScope) : (AcnFuncBodyResult option)= - let funBodyWithState st errCode prms p = + let newFuncBody (codec:Codec) (prms:((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list)) (nestingScope: NestingScope) (p:CallerScope): AcnFuncBodyResult option= + let funBodyWithState st errCode prms nestingScope p = let funcBody codec = match codec with Codec.Encode -> funcBodyEncode | Codec.Decode -> funcBodyDecode - funcBody codec prms p, st - let retFunc = DAstACN.handleSavePosition funBodyWithState ch.Type.savePosition c_name ch.id lm codec prms p - retFunc emptyState {ErrorCode.errCodeName = ""; ErrorCode.errCodeValue=0; comment=None} prms p |> fst + funcBody codec prms nestingScope p, st + let retFunc = DAstACN.handleSavePosition funBodyWithState ch.Type.savePosition c_name ch.id lm codec + retFunc emptyState {ErrorCode.errCodeName = ""; ErrorCode.errCodeValue=0; comment=None} prms nestingScope p |> fst let tdBodyWithinSeq = DAstACN.getDeterminantTypeDefinitionBodyWithinSeq r lm (Asn1AcnAst.AcnChildDeterminant ch) let initExpression = @@ -962,4 +962,3 @@ let DoWork (r:Asn1AcnAst.AstRoot) (icdStgFileName:string) (deps:Asn1AcnAst.AcnIn deps = deps icdHashes = ns.icdHashes } - diff --git a/BackendAst/DAstUPer.fs b/BackendAst/DAstUPer.fs index 3848a3b04..665817eae 100644 --- a/BackendAst/DAstUPer.fs +++ b/BackendAst/DAstUPer.fs @@ -62,7 +62,17 @@ let joinedOrAsIdentifier (lm: LanguageMacros) (codec: CommonTypes.Codec) (p: Cal //2.Fragmentation -let internal createUperFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (funcBody_e:ErrorCode->CallerScope -> (UPERFuncBodyResult option)) soSparkAnnotations (funcDefAnnots: string list) (us:State) = +let internal createUperFunction (r:Asn1AcnAst.AstRoot) + (lm:LanguageMacros) + (codec:CommonTypes.Codec) + (t:Asn1AcnAst.Asn1Type) + (typeDefinition:TypeDefinitionOrReference) + (baseTypeUperFunc : UPerFunction option) + (isValidFunc: IsValidFunction option) + (funcBody_e: ErrorCode -> NestingScope -> CallerScope -> UPERFuncBodyResult option) + soSparkAnnotations + (funcDefAnnots: string list) + (us:State) = let typeDef = lm.lg.getTypeDefinition t.FT_TypeDefinition let funcName = getFuncName r lm codec t.id typeDef let errCodeName = ToC ("ERR_UPER" + (codec.suffix.ToUpper()) + "_" + ((t.id.AcnAbsPath |> Seq.skip 1 |> Seq.StrJoin("-")).Replace("#","elm"))) @@ -82,7 +92,7 @@ let internal createUperFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (code match funcName with | None -> None, None | Some funcName -> - let content = funcBody p + let content = funcBody (NestingScope.init t.acnMaxSizeInBits t.uperMaxSizeInBits) p let bodyResult_funcBody, errCodes, bodyResult_localVariables, bBsIsUnreferenced, bVarNameIsUnreferenced = match content with | None -> @@ -141,7 +151,7 @@ let castPp (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) codec pp (intClass:Asn1Acn | CommonTypes.Decode -> pp -let getIntfuncBodyByCons (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (uperRange:BigIntegerUperRange) errLoc (intClass:Asn1AcnAst.IntegerClass) (cons: IntegerTypeConstraint list) (allCons: IntegerTypeConstraint list) (errCode:ErrorCode) (p:CallerScope) = +let getIntfuncBodyByCons (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (uperRange:BigIntegerUperRange) errLoc (intClass:Asn1AcnAst.IntegerClass) (cons: IntegerTypeConstraint list) (allCons: IntegerTypeConstraint list) (typeId: ReferenceToType) (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let IntNoneRequired = lm.uper.IntNoneRequired @@ -155,23 +165,23 @@ let getIntfuncBodyByCons (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Commo let IntRootExt2 = lm.uper.IntRootExt2 let rootCons = cons |> List.choose(fun x -> match x with RangeRootConstraint(_, a) |RangeRootConstraint2(_, a,_) -> Some(x) |_ -> None) - let checkExp = - //match (DastValidate2.createIntegerFunctionByCons r l isUnsigned allCons) with - //| None -> None - //| Some expFunc -> Some (expFunc p) - None let suffix = getIntDecFuncSuffix intClass let castPp encFuncBits = castPp r lm codec pp intClass encFuncBits - let IntBod uperRange extCon = + let rangeAssert = + match typeId.topLevelTas with + | Some tasInfo -> + lm.lg.generateIntFullyConstraintRangeAssert (ToC (r.args.TypePrefix + tasInfo.tasName)) p codec + | None -> None + let IntBod (uperRange: uperRange) (extCon: bool) : string * bool * bool * Asn1IntegerEncodingType option = match uperRange with - | Concrete(min, max) when min=max -> IntNoneRequired (lm.lg.getValue p.arg) (lm.lg.intValueToString min intClass) errCode.errCodeName codec, codec=Decode, true - | Concrete(min, max) when intClass.IsPositive && (not extCon) -> IntFullyConstraintPos (castPp ((int r.args.integerSizeInBytes)*8)) min max (GetNumberOfBitsForNonNegativeInteger (max-min)) suffix errCode.errCodeName codec, false, false - | Concrete(min, max) -> IntFullyConstraint (castPp ((int r.args.integerSizeInBytes)*8)) min max (GetNumberOfBitsForNonNegativeInteger (max-min)) suffix errCode.errCodeName codec, false, false - | PosInf(a) when a>=0I && (not extCon) -> IntSemiConstraintPos pp a errCode.errCodeName codec, false, false - | PosInf(a) -> IntSemiConstraint pp a errCode.errCodeName codec, false, false - | NegInf(max) -> IntUnconstrainedMax pp max checkExp errCode.errCodeName codec, false, false - | Full -> IntUnconstrained pp errCode.errCodeName false codec, false, false + | Concrete (min, max) when min=max -> IntNoneRequired (lm.lg.getValue p.arg) (lm.lg.intValueToString min intClass) errCode.errCodeName codec, codec=Decode, true, None + | Concrete (min, max) when intClass.IsPositive && (not extCon) -> IntFullyConstraintPos (castPp ((int r.args.integerSizeInBytes)*8)) min max (GetNumberOfBitsForNonNegativeInteger (max-min)) suffix errCode.errCodeName rangeAssert codec, false, false, Some (FullyConstrainedPositive (min, max)) + | Concrete (min, max) -> IntFullyConstraint (castPp ((int r.args.integerSizeInBytes)*8)) min max (GetNumberOfBitsForNonNegativeInteger (max-min)) suffix errCode.errCodeName codec, false, false, Some (FullyConstrained (min, max)) + | PosInf a when a>=0I && (not extCon) -> IntSemiConstraintPos pp a errCode.errCodeName codec, false, false, Some (SemiConstrainedPositive a) + | PosInf a -> IntSemiConstraint pp a errCode.errCodeName codec, false, false, Some (SemiConstrained a) + | NegInf max -> IntUnconstrainedMax pp max None errCode.errCodeName codec, false, false, Some (UnconstrainedMax max) + | Full -> IntUnconstrained pp errCode.errCodeName false codec, false, false, Some Unconstrained let getValueByConstraint uperRange = match uperRange with @@ -179,73 +189,68 @@ let getIntfuncBodyByCons (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Commo | PosInf(a) -> a | NegInf(b) -> b | Full -> 0I - let funcBodyContent, bValIsUnReferenced, bBsIsUnReferenced = + let funcBodyContent, bValIsUnReferenced, bBsIsUnReferenced, intEncodingType = match rootCons with | [] -> IntBod uperRange false | (RangeRootConstraint (_, a))::rest -> let uperR = uPER.getIntTypeConstraintUperRange [a] errLoc let cc,_ = DastValidate2.integerConstraint2ValidationCodeBlock r lm intClass a 0 let cc = DastValidate2.ValidationBlockAsStringExpr (cc p) - //let cc = DAstValidate.foldRangeCon l (fun v -> v.ToString()) (fun v -> v.ToString()) p a - let rootBody, _,_ = IntBod uperR true - IntRootExt pp (getValueByConstraint uperR) cc rootBody errCode.errCodeName codec, false, false + let rootBody, _,_, intEncodingType = IntBod uperR true + IntRootExt pp (getValueByConstraint uperR) cc rootBody errCode.errCodeName codec, false, false, intEncodingType | (RangeRootConstraint2(_,a,_))::rest -> let uperR = uPER.getIntTypeConstraintUperRange [a] errLoc - //let cc = DAstValidate.foldRangeCon l (fun v -> v.ToString()) (fun v -> v.ToString()) p a let cc,_ = DastValidate2.integerConstraint2ValidationCodeBlock r lm intClass a 0 let cc = DastValidate2.ValidationBlockAsStringExpr (cc p) - let rootBody, _,_ = IntBod uperR true - IntRootExt2 pp (getValueByConstraint uperR) cc rootBody errCode.errCodeName codec, false, false + let rootBody, _,_, intEncodingType = IntBod uperR true + IntRootExt2 pp (getValueByConstraint uperR) cc rootBody errCode.errCodeName codec, false, false, intEncodingType | _ -> raise(BugErrorException "") - Some({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=bValIsUnReferenced; bBsIsUnReferenced=bBsIsUnReferenced; resultExpr=resultExpr}) - - - + Some({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=bValIsUnReferenced; bBsIsUnReferenced=bBsIsUnReferenced; resultExpr=resultExpr; typeEncodingKind=Some (Asn1IntegerEncodingType intEncodingType)}) let createIntegerFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Integer) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = - getIntfuncBodyByCons r lm codec o.uperRange t.Location (o.intClass) o.cons o.AllCons errCode p + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = + getIntfuncBodyByCons r lm codec o.uperRange t.Location o.intClass o.cons o.AllCons t.id errCode nestingScope p let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> funcBody e p) soSparkAnnotations [] us let createBooleanFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Boolean) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let Boolean = lm.uper.Boolean let funcBodyContent = Boolean pp errCode.errCodeName codec - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnBooleanEncodingType None)} let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us let castRPp = DAstEqual.castRPp let createRealFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Real) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = + let cls = o.getClass r.args let sSuffix = - match o.getClass r.args with + match cls with | ASN1SCC_REAL -> "" | ASN1SCC_FP32 -> "_fp32" | ASN1SCC_FP64 -> "" - - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgument lm codec p let castPp = castRPp lm codec (o.getClass r.args) pp let Real = lm.uper.Real let funcBodyContent = Real castPp sSuffix errCode.errCodeName codec - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (Asn1RealEncodingType cls)} let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) let annots = match ST.lang with | Scala -> ["extern"] | _ -> [] - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations annots us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations annots us let createObjectIdentifierFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.ObjectIdentifier) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgumentPtr lm codec p let ObjectIdentifier = if o.relativeObjectId then @@ -253,9 +258,9 @@ let createObjectIdentifierFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) ( else lm.uper.ObjectIdentifier let funcBodyContent = ObjectIdentifier pp errCode.errCodeName codec - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some Placeholder} // TODO: Placeholder let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us let getTimeSubTypeByClass (tc) = match tc with @@ -269,26 +274,26 @@ let getTimeSubTypeByClass (tc) = let createTimeTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.TimeType) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, resultExpr = adaptArgumentPtr lm codec p let TimeType = lm.uper.Time let funcBodyContent = TimeType pp (getTimeSubTypeByClass o.timeClass) errCode.errCodeName codec - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some Placeholder} // TODO: Placeholder let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us let createNullTypeFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.NullType) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let pp, _ = adaptArgument lm codec p match codec, lm.lg.decodingKind with | Decode, Copy -> - Some ({UPERFuncBodyResult.funcBody = lm.uper.Null_declare pp; errCodes = []; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=Some pp}) + Some ({UPERFuncBodyResult.funcBody = lm.uper.Null_declare pp; errCodes = []; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=Some pp; typeEncodingKind=Some (AcnNullEncodingType None)}) | _ -> None let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc funcBody soSparkAnnotations [] us let createEnumeratedFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Enumerated) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let Enumerated = lm.uper.Enumerated let Enumerated_item = lm.uper.Enumerated_item let typeDef0 = lm.lg.getEnumTypeDefinition o.typeDef @@ -302,9 +307,9 @@ let createEnumeratedFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let nBits = (GetNumberOfBitsForNonNegativeInteger (nMax-nMin)) let sFirstItemName = lm.lg.getNamedItemBackendName (Some typeDefinition) o.items.Head let funcBodyContent = Enumerated pp td items nMin nMax nBits errCode.errCodeName nLastItemIndex sFirstItemName codec - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (Asn1IntegerEncodingType (Some (FullyConstrained (nMin, nMax))))} let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us let C64K = BigInteger 0x10000 let C48K = BigInteger 0xC000 @@ -412,7 +417,7 @@ let createIA5StringFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Co match o.minSize.uper = o.maxSize.uper with | true -> [] | false -> [lm.lg.uper.createLv "nStringLength"] - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let td0 = lm.lg.getStrTypeDefinition o.typeDef let td = td0.longTypedefName2 lm.lg.hasModules (ToC p.modName) let InternalItem_string_no_alpha = lm.uper.InternalItem_string_no_alpha @@ -435,10 +440,32 @@ let createIA5StringFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Co | Decode, Copy -> Some (lm.lg.initializeString (int o.maxSize.uper)) | _ -> None let pp, resultExpr = joinedOrAsIdentifier lm codec p + + let sqfProofGen = { + SequenceOfLikeProofGen.acnOuterMaxSize = nestingScope.acnOuterMaxSize + uperOuterMaxSize = nestingScope.uperOuterMaxSize + nestingLevel = nestingScope.nestingLevel + nestingIx = nestingScope.nestingIx + acnMaxOffset = nestingScope.acnOffset + uperMaxOffset = nestingScope.uperOffset + typeInfo = { + uperMaxSizeBits = nBits + acnMaxSizeBits = nBits + typeKind = Some (AcnStringEncodingType o.acnEncodingClass) // TODO: Check this + } + sel = pp + ixVariable = i + } + let sqfProofGenRes = lm.lg.generateSequenceOfLikeProof ACN (SequenceOfLike.StrType o) sqfProofGen codec + let preSerde = sqfProofGenRes |> Option.map (fun r -> r.preSerde) + let postSerde = sqfProofGenRes |> Option.map (fun r -> r.postSerde) + let postInc = sqfProofGenRes |> Option.map (fun r -> r.postInc) + let invariant = sqfProofGenRes |> Option.map (fun r -> r.invariant) + let introSnap = nestingScope.nestingLevel = 0 let funcBodyContent,localVariables = match o.minSize with | _ when o.maxSize.uper < 65536I && o.maxSize.uper=o.minSize.uper -> - str_FixedSize pp typeDefinitionName i internalItem o.minSize.uper nBits nBits 0I initExpr codec, lv::charIndex@nStringLength + str_FixedSize pp typeDefinitionName i internalItem o.minSize.uper nBits nBits 0I initExpr introSnap preSerde postSerde postInc invariant codec, lv::charIndex@nStringLength | _ when o.maxSize.uper < 65536I && o.maxSize.uper<>o.minSize.uper -> str_VarSize pp typeDefinitionName i internalItem o.minSize.uper o.maxSize.uper nSizeInBits nBits nBits 0I initExpr codec, lv::charIndex@nStringLength | _ -> @@ -446,13 +473,13 @@ let createIA5StringFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Co let localVariables = localVariables |> List.addIf (lm.lg.uper.requires_IA5String_i || o.maxSize.uper<>o.minSize.uper) lv funcBodyContent, charIndex@localVariables - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnStringEncodingType o.acnEncodingClass)} let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us -let createOctetStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (id : ReferenceToType) (typeDefinition:TypeDefinitionOrReference) isFixedSize uperMaxSizeInBits minSize maxSize (errCode:ErrorCode) (p:CallerScope) = +let createOctetStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (id : ReferenceToType) (typeDefinition:TypeDefinitionOrReference) isFixedSize uperMaxSizeInBits minSize maxSize (o:Asn1AcnAst.OctetString) (errCode:ErrorCode) (p:CallerScope) = let ii = id.SequenceOfLevel + 1; let i = sprintf "i%d" ii let lv = SequenceOfIndex (id.SequenceOfLevel + 1, None) @@ -483,17 +510,17 @@ let createOctetStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros let localVariables = localVariables |> List.addIf (lm.lg.uper.requires_IA5String_i || (not isFixedSize)) (lv) funcBodyContent, localVariables - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnOctetStringEncodingType o.acnEncodingClass)} let createOctetStringFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.OctetString) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = - createOctetStringFunction_funcBody r lm codec t.id typeDefinition o.isFixedSize o.uperMaxSizeInBits o.minSize.uper o.maxSize.uper (errCode:ErrorCode) (p:CallerScope) + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = + createOctetStringFunction_funcBody r lm codec t.id typeDefinition o.isFixedSize o.uperMaxSizeInBits o.minSize.uper o.maxSize.uper o (errCode:ErrorCode) (p:CallerScope) let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us @@ -502,7 +529,7 @@ let createBitStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) lm.lg.uper.createBitStringFunction (handleFragmentation lm) codec id typeDefinition isFixedSize uperMaxSizeInBits minSize maxSize errCode p *) -let createBitStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (id : ReferenceToType) (typeDefinition:TypeDefinitionOrReference) isFixedSize uperMaxSizeInBits minSize maxSize (errCode:ErrorCode) (p:CallerScope) = +let createBitStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (id : ReferenceToType) (typeDefinition:TypeDefinitionOrReference) isFixedSize uperMaxSizeInBits minSize maxSize (o:Asn1AcnAst.BitString) (errCode:ErrorCode) (p:CallerScope) = let bitString_FixSize = lm.uper.bitString_FixSize let bitString_VarSize = lm.uper.bitString_VarSize let ii = id.SequenceOfLevel + 1; @@ -529,16 +556,16 @@ let createBitStringFunction_funcBody (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) let fragmentationLvars = fragmentationLvars |> List.addIf ((not isFixedSize) && lm.lg.uper.requires_sBLJ) (iVar) (funcBodyContent,fragmentationLvars) - {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} + {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (AcnBitStringEncodingType o.acnEncodingClass)} let createBitStringFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.BitString) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (us:State) = - let funcBody (errCode:ErrorCode) (p:CallerScope) = - createBitStringFunction_funcBody r lm codec t.id typeDefinition o.isFixedSize o.uperMaxSizeInBits o.minSize.uper o.maxSize.uper (errCode:ErrorCode) (p:CallerScope) + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = + createBitStringFunction_funcBody r lm codec t.id typeDefinition o.isFixedSize o.uperMaxSizeInBits o.minSize.uper o.maxSize.uper o (errCode:ErrorCode) (p:CallerScope) let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e p -> Some (funcBody e p)) soSparkAnnotations [] us + createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc (fun e ns p -> Some (funcBody e ns p)) soSparkAnnotations [] us let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.SequenceOf) (typeDefinition:TypeDefinitionOrReference) (baseTypeUperFunc : UPerFunction option) (isValidFunc: IsValidFunction option) (child:Asn1Type) (us:State) = @@ -549,11 +576,12 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let nIntItemMaxSize = ( child.uperMaxSizeInBits) let baseFuncName = match baseTypeUperFunc with None -> None | Some baseFunc -> baseFunc.funcName - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = match baseFuncName with | None -> let pp, resultExpr = joinedOrAsIdentifier lm codec p + let childNestingScope = {nestingScope with nestingLevel = nestingScope.nestingLevel + 1} let access = lm.lg.getAccess p.arg // `childInitExpr` is used to initialize the array of elements in which we will write their decoded values // It is only meaningful for "Copy" decoding kind, since InPlace will directly modify `p`'s array @@ -571,18 +599,46 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let chFunc = child.getUperFunction codec let internalItem = - chFunc.funcBody ({p with arg = lm.lg.getArrayItem p.arg i child.isIA5String}) + chFunc.funcBody childNestingScope ({p with arg = lm.lg.getArrayItem p.arg i child.isIA5String}) + + let sqfProofGen = { + SequenceOfLikeProofGen.acnOuterMaxSize = nestingScope.acnOuterMaxSize + uperOuterMaxSize = nestingScope.uperOuterMaxSize + nestingLevel = nestingScope.nestingLevel + nestingIx = nestingScope.nestingIx + acnMaxOffset = nestingScope.acnOffset + uperMaxOffset = nestingScope.uperOffset + typeInfo = { + uperMaxSizeBits = child.uperMaxSizeInBits + acnMaxSizeBits = child.acnMaxSizeInBits + typeKind = internalItem |> Option.bind (fun i -> i.typeEncodingKind) + } + sel = pp + ixVariable = i + } + let sqfProofGenRes = lm.lg.generateSequenceOfLikeProof ACN (SqOf o) sqfProofGen codec + let preSerde = sqfProofGenRes |> Option.map (fun r -> r.preSerde) + let postSerde = sqfProofGenRes |> Option.map (fun r -> r.postSerde) + let postInc = sqfProofGenRes |> Option.map (fun r -> r.postInc) + let invariant = sqfProofGenRes |> Option.map (fun r -> r.invariant) + + let absOffset = nestingScope.uperOffset + let remBits = nestingScope.uperOuterMaxSize - nestingScope.uperOffset + let lvl = bigint (max 0 (nestingScope.nestingLevel - 1)) + let ix = bigint nestingScope.nestingIx + 1I + let offset = nestingScope.uperRelativeOffset + let introSnap = nestingScope.nestingLevel = 0 match internalItem with | None -> match o.minSize with | _ when o.maxSize.uper < 65536I && o.maxSize.uper=o.minSize.uper -> None | _ when o.maxSize.uper < 65536I && o.maxSize.uper<>o.minSize.uper -> - let funcBody = varSize pp access td i "" ( o.minSize.uper) ( o.maxSize.uper) nSizeInBits ( child.uperMinSizeInBits) nIntItemMaxSize 0I childInitExpr errCode.errCodeName codec - Some ({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = lv@nStringLength; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + let funcBody = varSize pp access td i "" o.minSize.uper o.maxSize.uper nSizeInBits child.uperMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName absOffset remBits lvl ix offset introSnap preSerde postSerde postInc invariant codec + Some ({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = lv@nStringLength; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=None}) | _ -> let funcBody, localVariables = handleFragmentation lm p codec errCode ii ( o.uperMaxSizeInBits) o.minSize.uper o.maxSize.uper "" nIntItemMaxSize false false - Some ({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + Some ({UPERFuncBodyResult.funcBody = funcBody; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=None}) | Some internalItem -> let childErrCodes = internalItem.errCodes let internalItemBody = @@ -593,27 +649,33 @@ let createSequenceOfFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C | _ -> internalItem.funcBody let ret,localVariables = match o.minSize with - | _ when o.maxSize.uper < 65536I && o.maxSize.uper=o.minSize.uper -> fixedSize pp td i internalItemBody ( o.minSize.uper) ( child.uperMinSizeInBits) nIntItemMaxSize 0I childInitExpr codec, nStringLength - | _ when o.maxSize.uper < 65536I && o.maxSize.uper<>o.minSize.uper -> varSize pp access td i internalItemBody ( o.minSize.uper) ( o.maxSize.uper) nSizeInBits ( child.uperMinSizeInBits) nIntItemMaxSize 0I childInitExpr errCode.errCodeName codec , nStringLength + | _ when o.maxSize.uper < 65536I && o.maxSize.uper=o.minSize.uper -> fixedSize pp td i internalItemBody o.minSize.uper child.uperMinSizeInBits nIntItemMaxSize 0I childInitExpr codec, nStringLength + | _ when o.maxSize.uper < 65536I && o.maxSize.uper<>o.minSize.uper -> varSize pp access td i internalItemBody o.minSize.uper o.maxSize.uper nSizeInBits child.uperMinSizeInBits nIntItemMaxSize 0I childInitExpr errCode.errCodeName absOffset remBits lvl ix offset introSnap preSerde postSerde postInc invariant codec , nStringLength | _ -> handleFragmentation lm p codec errCode ii ( o.uperMaxSizeInBits) o.minSize.uper o.maxSize.uper internalItemBody nIntItemMaxSize false false - - Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childErrCodes; localVariables = lv@(localVariables@internalItem.localVariables); bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + let typeEncodingKind = internalItem.typeEncodingKind |> Option.map (fun tpe -> TypeEncodingKind.SequenceOfEncodingType (tpe, o.acnEncodingClass)) + Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childErrCodes; localVariables = lv@(localVariables@internalItem.localVariables); bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=typeEncodingKind}) | Some baseFuncName -> let pp, resultExpr = adaptArgumentPtr lm codec p let funcBodyContent = callBaseTypeFunc lm pp baseFuncName codec - Some ({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + Some ({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=None}) let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) createUperFunction r lm codec t typeDefinition baseTypeUperFunc isValidFunc funcBody soSparkAnnotations [] us +type private SequenceChildState = { + childIx: int + uperAccBits: BigInteger + acnAccBits: BigInteger +} type private SequenceChildStmt = { body: string option lvs: LocalVariable list errCodes: ErrorCode list } type private SequenceChildResult = { - presenceBit: string option stmt: SequenceChildStmt option resultExpr: string option + props: SequenceChildProps + typeEncodingKind: TypeEncodingKind option } let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:CommonTypes.Codec) (t:Asn1AcnAst.Asn1Type) (o:Asn1AcnAst.Sequence) (typeDefinition:TypeDefinitionOrReference) (isValidFunc: IsValidFunction option) (children:SeqChildInfo list) (us:State) = @@ -627,7 +689,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com let td = typeDefinition.longTypedefName2 lm.lg.hasModules - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let nonAcnChildren = children |> List.choose(fun c -> match c with Asn1Child c -> Some c | AcnChild _ -> None) let localVariables = match nonAcnChildren |> Seq.exists(fun x -> x.Optionality.IsSome) with @@ -636,14 +698,40 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com let pp, resultExpr = joinedOrAsIdentifier lm codec p let access = lm.lg.getAccess p.arg - let handleChild (child:Asn1Child): SequenceChildResult = + let printPresenceBit (child: Asn1Child): string option = + let childName = lm.lg.getAsn1ChildBackendName child + let existVar = + match codec, lm.lg.decodingKind with + | Decode, Copy -> Some (ToC (child._c_name + "_exist")) + | _ -> None + let absent, present = + match ST.lang with + | Scala -> "false", "true" + | _ -> "0", "1" + // please note that in decode, macro uper_sequence_presence_bit_fix + // calls macro uper_sequence_presence_bit (i.e. behaves like optional) + let seq_presence_bit_fix (value: string) = + sequence_presence_bit_fix pp access childName existVar errCode.errCodeName value codec + match child.Optionality with + | None -> None + | Some Asn1AcnAst.AlwaysAbsent -> Some (seq_presence_bit_fix absent) + | Some Asn1AcnAst.AlwaysPresent -> Some (seq_presence_bit_fix present) + | Some (Asn1AcnAst.Optional opt) -> Some (sequence_presence_bit pp access childName existVar errCode.errCodeName codec) + + let handleChild (s: SequenceChildState) (child:Asn1Child): SequenceChildResult * SequenceChildState = let childName = lm.lg.getAsn1ChildBackendName child let childTypeDef = child.Type.typeDefinitionOrReference.longTypedefName2 lm.lg.hasModules + let childNestingScope = + {nestingScope with + nestingLevel = nestingScope.nestingLevel + 1 + nestingIx = nestingScope.nestingIx + s.childIx + uperRelativeOffset = s.uperAccBits + uperOffset = nestingScope.uperOffset + s.uperAccBits} let chFunc = child.Type.getUperFunction codec let newArg = lm.lg.getSeqChild p.arg childName child.Type.isIA5String child.Optionality.IsSome let newArg = if lm.lg.usesWrappedOptional && newArg.isOptional && codec = Encode then newArg.asLast else newArg let childP = {p with arg = newArg} - let childContentResult = chFunc.funcBody childP + let childContentResult = chFunc.funcBody childNestingScope childP let existVar = match codec, lm.lg.decodingKind with | Decode, Copy -> Some (ToC (child._c_name + "_exist")) @@ -663,6 +751,10 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com | Some Asn1AcnAst.AlwaysPresent -> Some (seq_presence_bit_fix present) | Some (Asn1AcnAst.Optional opt) -> Some (sequence_presence_bit pp access childName existVar errCode.errCodeName codec) + let typeInfo = {uperMaxSizeBits=child.uperMaxSizeInBits; acnMaxSizeBits=child.acnMaxSizeInBits; typeKind=childContentResult |> Option.bind (fun c -> c.typeEncodingKind)} + let props = {sel=Some (childP.arg.joined lm.lg); uperMaxOffset=s.uperAccBits; acnMaxOffset=s.acnAccBits; typeInfo=typeInfo} + let newAcc = {childIx=s.childIx + 1; uperAccBits=s.uperAccBits + child.uperMaxSizeInBits; acnAccBits=s.acnAccBits + child.acnMaxSizeInBits} + match childContentResult with | None -> // Copy-decoding expects to have a result expression (even if unused), so we pick the initExpression @@ -670,7 +762,7 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com match codec, lm.lg.decodingKind with | Decode, Copy -> Some child.Type.initFunction.initExpression | _ -> None - {presenceBit=presenceBit; stmt=None; resultExpr=childResultExpr} + {stmt=None; resultExpr=childResultExpr; props=props; typeEncodingKind=None}, newAcc | Some childContent -> let childBody, child_localVariables = match child.Optionality with @@ -692,22 +784,40 @@ let createSequenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Com | Some v -> let defInit= child.Type.initFunction.initByAsn1Value childP (mapValue v).kind Some (sequence_default_child pp access childName childContent.funcBody existVar childContent.resultExpr childTypeDef defInit codec), childContent.localVariables - {presenceBit=presenceBit; stmt=Some {body=childBody; lvs=child_localVariables; errCodes=childContent.errCodes}; resultExpr=childContent.resultExpr} + {stmt=Some {body=childBody; lvs=child_localVariables; errCodes=childContent.errCodes}; resultExpr=childContent.resultExpr; props=props; typeEncodingKind=childContent.typeEncodingKind}, newAcc + + let presenceBits = nonAcnChildren |> List.map printPresenceBit + let nbPresenceBits = presenceBits |> List.sumBy (fun s -> if s.IsSome then 1I else 0I) + let childrenStatements00, _ = nonAcnChildren |> foldMap handleChild {childIx=0; uperAccBits=nbPresenceBits; acnAccBits=nbPresenceBits} + + let seqProofGen = + let presenceBitsInfo = presenceBits |> List.mapi (fun i _ -> + {sel=None; uperMaxOffset = bigint i; acnMaxOffset = bigint i; + typeInfo = {uperMaxSizeBits = 1I; acnMaxSizeBits = 1I; typeKind = Some (AcnBooleanEncodingType None)};}) + let children = childrenStatements00 |> List.map (fun xs -> xs.props) + {acnOuterMaxSize = nestingScope.acnOuterMaxSize; uperOuterMaxSize = nestingScope.uperOuterMaxSize; + nestingLevel = nestingScope.nestingLevel; nestingIx = nestingScope.nestingIx; + uperMaxOffset = nestingScope.uperOffset; acnMaxOffset = nestingScope.acnOffset; + acnSiblingMaxSize = nestingScope.acnSiblingMaxSize; uperSiblingMaxSize = nestingScope.uperSiblingMaxSize; + children = presenceBitsInfo @ children} + let allStmts = + let children = childrenStatements00 |> List.map (fun s -> s.stmt |> Option.bind (fun stmt -> stmt.body)) + presenceBits @ children + let childrenStatements = lm.lg.generateSequenceChildProof UPER allStmts seqProofGen codec - let childrenStatements00 = nonAcnChildren |> List.map handleChild - let presenceBits = childrenStatements00 |> List.choose (fun s -> s.presenceBit) let childrenStatements0 = childrenStatements00 |> List.choose(fun s -> s.stmt) - let childrenStatements = childrenStatements0 |> List.choose(fun s -> s.body) let childrenLocalVars = childrenStatements0 |> List.collect(fun s -> s.lvs) let childrenErrCodes = childrenStatements0 |> List.collect(fun s -> s.errCodes) let childrenResultExpr = childrenStatements00 |> List.choose(fun s -> s.resultExpr) + let childrenTypeKindEncoding = childrenStatements00 |> List.map(fun s -> s.typeEncodingKind) + // If we are Decoding with Copy decoding kind, then all children `resultExpr` must be defined as well (i.e. we must have the same number of `resultExpr` as children) assert (resultExpr.IsNone || childrenResultExpr.Length = nonAcnChildren.Length) let seqBuild = resultExpr |> Option.map (fun res -> sequence_build res td childrenResultExpr) |> Option.toList - let seqContent = (presenceBits@childrenStatements@seqBuild) |> nestChildItems lm codec + let seqContent = (childrenStatements@seqBuild) |> nestChildItems lm codec match seqContent with | None -> None - | Some ret -> Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalVars; bValIsUnReferenced=false; bBsIsUnReferenced=(o.uperMaxSizeInBits = 0I); resultExpr=resultExpr}) + | Some ret -> Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalVars; bValIsUnReferenced=false; bBsIsUnReferenced=(o.uperMaxSizeInBits = 0I); resultExpr=resultExpr; typeEncodingKind=Some (SequenceEncodingType childrenTypeKindEncoding)}) let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) createUperFunction r lm codec t typeDefinition None isValidFunc funcBody soSparkAnnotations [] us @@ -728,17 +838,20 @@ let createChoiceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Commo let typeDefinitionName = typeDefinition.longTypedefName2 lm.lg.hasModules - let funcBody (errCode:ErrorCode) (p:CallerScope) = + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = let td0 = lm.lg.getChoiceTypeDefinition o.typeDef let td = td0.longTypedefName2 lm.lg.hasModules (ToC p.modName) + let acnSiblingMaxSize = children |> List.map (fun c -> c.chType.acnMaxSizeInBits) |> List.max + let uperSiblingMaxSize = children |> List.map (fun c -> c.chType.uperMaxSizeInBits) |> List.max - let handleChild (nIndexSizeInBits: BigInteger) (i: int) (child: ChChildInfo): string * LocalVariable list * ErrorCode list = + let handleChild (nIndexSizeInBits: BigInteger) (i: int) (child: ChChildInfo): string * LocalVariable list * ErrorCode list * TypeEncodingKind option = + let childNestingScope = {nestingScope with nestingLevel = nestingScope.nestingLevel + 1; uperSiblingMaxSize = Some uperSiblingMaxSize; acnSiblingMaxSize = Some acnSiblingMaxSize} let chFunc = child.chType.getUperFunction codec let uperChildRes = match lm.lg.uper.catd with - | false -> chFunc.funcBody ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) - | true when codec = CommonTypes.Decode -> chFunc.funcBody ({p with arg = Selection.valueEmptyPath ((lm.lg.getAsn1ChChildBackendName child) + "_tmp")}) - | true -> chFunc.funcBody ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) + | false -> chFunc.funcBody childNestingScope ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) + | true when codec = CommonTypes.Decode -> chFunc.funcBody childNestingScope {p with arg = Selection.valueEmptyPath ((lm.lg.getAsn1ChChildBackendName child) + "_tmp")} + | true -> chFunc.funcBody childNestingScope ({p with arg = lm.lg.getChChild p.arg (lm.lg.getAsn1ChChildBackendName child) child.chType.isIA5String}) let sChildName = (lm.lg.getAsn1ChChildBackendName child) let sChildTypeDef = child.chType.typeDefinitionOrReference.longTypedefName2 lm.lg.hasModules let isSequence = match child.chType.Kind with | Sequence _ -> true | _ -> false @@ -761,24 +874,27 @@ let createChoiceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:Commo | Sequence _ -> uper_a.decode_empty_sequence_emptySeq childp.arg.receiverId | _ -> lm.lg.createSingleLineComment "no encoding/decoding is required" | true -> lm.lg.createSingleLineComment "no encoding/decoding is required" - mk_choice_child childContent, [], [] + mk_choice_child childContent, [], [], None | Some childContent -> - mk_choice_child childContent.funcBody, childContent.localVariables, childContent.errCodes + mk_choice_child childContent.funcBody, childContent.localVariables, childContent.errCodes, childContent.typeEncodingKind match baseFuncName with | None -> let nIndexSizeInBits = (GetNumberOfBitsForNonNegativeInteger (BigInteger (children.Length - 1))) let childrenContent3 = children |> List.mapi (handleChild nIndexSizeInBits) - let childrenContent = childrenContent3 |> List.map(fun (s,_,_) -> s) - let childrenLocalvars = childrenContent3 |> List.collect(fun (_,s,_) -> s) - let childrenErrCodes = childrenContent3 |> List.collect(fun (_,_,s) -> s) + let childrenContent = childrenContent3 |> List.map(fun (s,_,_,_) -> s) + let childrenLocalvars = childrenContent3 |> List.collect(fun (_,s,_,_) -> s) + let childrenErrCodes = childrenContent3 |> List.collect(fun (_,_,s,_) -> s) + let childrenTypeKindEncoding = childrenContent3 |> List.map(fun (_,_,_,s) -> s) + let introSnap = nestingScope.nestingLevel = 0 let pp, resultExpr = joinedOrAsIdentifier lm codec p - let ret = choice pp (lm.lg.getAccess p.arg) childrenContent (BigInteger (children.Length - 1)) sChoiceIndexName errCode.errCodeName td nIndexSizeInBits codec - Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + let ret = choice pp (lm.lg.getAccess p.arg) childrenContent (BigInteger (children.Length - 1)) sChoiceIndexName errCode.errCodeName td nIndexSizeInBits introSnap codec + Some ({UPERFuncBodyResult.funcBody = ret; errCodes = errCode::childrenErrCodes; localVariables = localVariables@childrenLocalvars; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (ChoiceEncodingType childrenTypeKindEncoding)}) | Some baseFuncName -> let pp, resultExpr = adaptArgumentPtr lm codec p let funcBodyContent = callBaseTypeFunc lm pp baseFuncName codec - Some ({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr}) + // TODO: Qu'est-ce que c'est que ça???? + Some ({UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=None}) let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) @@ -794,9 +910,9 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C match TypesEquivalence.uperEquivalence t1 t1WithExtensions with | true -> let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - let funcBody (errCode:ErrorCode) (p:CallerScope) = - match (baseType.getUperFunction codec).funcBody p with - | Some _ -> + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = + match (baseType.getUperFunction codec).funcBody nestingScope p with + | Some _ -> let pp, resultExpr = let str = lm.lg.getParamValue t p.arg codec match codec, lm.lg.decodingKind with @@ -805,8 +921,8 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C toc, Some toc | _ -> str, None let funcBodyContent = callBaseTypeFunc lm pp baseFncName codec - Some {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false ; resultExpr=resultExpr} - | None -> None + Some {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (ReferenceEncodingType baseTypeDefinitionName)} + | None -> None createUperFunction r lm codec t typeDefinition None isValidFunc funcBody soSparkAnnotations [] us | false -> baseType.getUperFunction codec, us @@ -814,9 +930,9 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C let octet_string_containing_func = lm.uper.octet_string_containing_func let bit_string_containing_func = lm.uper.bit_string_containing_func let soSparkAnnotations = Some(sparkAnnotations lm (lm.lg.getLongTypedefName typeDefinition) codec) - let funcBody (errCode:ErrorCode) (p:CallerScope) = - match (baseType.getUperFunction codec).funcBody p with - | Some _ -> + let funcBody (errCode:ErrorCode) (nestingScope: NestingScope) (p:CallerScope) = + match (baseType.getUperFunction codec).funcBody nestingScope p with + | Some _ -> let pp, resultExpr = let str = lm.lg.getParamValue t p.arg codec match codec, lm.lg.decodingKind with @@ -831,6 +947,6 @@ let createReferenceFunction (r:Asn1AcnAst.AstRoot) (lm:LanguageMacros) (codec:C match opts.octOrBitStr with | ContainedInOctString -> octet_string_containing_func pp baseFncName sReqBytesForUperEncoding nBits opts.minSize.uper opts.maxSize.uper codec | ContainedInBitString -> bit_string_containing_func pp baseFncName sReqBytesForUperEncoding sReqBitForUperEncoding nBits opts.minSize.uper opts.maxSize.uper codec - Some {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr} - | None -> None + Some {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = []; bValIsUnReferenced=false; bBsIsUnReferenced=false; resultExpr=resultExpr; typeEncodingKind=Some (ReferenceEncodingType baseTypeDefinitionName)} + | None -> None createUperFunction r lm codec t typeDefinition None isValidFunc funcBody soSparkAnnotations [] us diff --git a/BackendAst/DAstUtilFunctions.fs b/BackendAst/DAstUtilFunctions.fs index c82833dd9..65317a872 100644 --- a/BackendAst/DAstUtilFunctions.fs +++ b/BackendAst/DAstUtilFunctions.fs @@ -16,13 +16,13 @@ let getAccessFromScopeNodeList (ReferenceToType nodes) (childTypeIsString: bool | TA _ | PRM _ | VA _ -> raise(BugErrorException "getAccessFromScopeNodeList") - | SEQ_CHILD (chName, chOpt) -> - let isPresent = + | SEQ_CHILD (chName, chOpt) -> + let isPresent = match chOpt with | true -> [lm.lg.getSeqChildIsPresent pVal.arg chName] //[sprintf "%s%sexist.%s" pVal.arg.p (lm.lg.getAccess pVal.arg) chName] | false -> [] isPresent, {pVal with arg = lm.lg.getSeqChild pVal.arg (ToC chName) childTypeIsString chOpt} - | CH_CHILD (chName, pre_name, chParent) -> + | CH_CHILD (chName, pre_name, chParent) -> let chChildIsPresent = match ST.lang with | Scala -> sprintf "%s.isInstanceOf[%s.%s_PRESENT]" (pVal.arg.joined lm.lg) chParent pre_name @@ -735,10 +735,37 @@ with | Some tasInfo -> Some tasInfo.AsTasInfo | None -> None +type Asn1Child with + member this.getBackendName l = + match l with + | C -> this._c_name + | Scala -> this._scala_name + | Ada -> this._ada_name + member this.acnMinSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.acnMinSizeInBits + member this.acnMaxSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.acnMaxSizeInBits -//let getValueType (r:AstRoot) (v:Asn1GenericValue) = -// r.typesMap.[v.refToType] + member this.uperMinSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.uperMinSizeInBits + + member this.uperMaxSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.uperMaxSizeInBits + + member this.maxSizeInBits (enc: Asn1Encoding): BigInteger = + match enc with + | UPER -> this.uperMaxSizeInBits + | ACN -> this.acnMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") type Asn1Module with member this.ExportedTypes = @@ -872,17 +899,26 @@ type SeqChildInfo with | AcnChild x -> None member this.acnMaxSizeInBits = match this with - | Asn1Child x -> x.Type.acnMaxSizeInBits + | Asn1Child x -> x.acnMaxSizeInBits // Takes into account ALWAYS ABSENT | AcnChild x -> x.Type.acnMaxSizeInBits member this.acnMinSizeInBits = match this with - | Asn1Child x -> x.Type.acnMinSizeInBits + | Asn1Child x -> x.acnMinSizeInBits | AcnChild x -> x.Type.acnMinSizeInBits member this.Comments = match this with | Asn1Child x -> x.Comments | AcnChild x -> [||] + member this.maxSizeInBits (enc: Asn1Encoding): BigInteger = + match enc with + | UPER -> + match this with + | Asn1Child x -> x.uperMaxSizeInBits + | AcnChild x -> raise (BugErrorException $"Unexpected UPER encoding for ACN child {x.Name}") + | ACN -> this.acnMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + let hasAcnEncodeFunction (encFunc : AcnFunction option) acnParameters = match encFunc with | None -> false @@ -890,7 +926,7 @@ let hasAcnEncodeFunction (encFunc : AcnFunction option) acnParameters = match acnParameters with | [] -> let p = {CallerScope.modName = ""; arg = Selection.valueEmptyPath "dummy"} - let ret,_ = fnc.funcBody emptyState [] p + let ret,_ = fnc.funcBody emptyState [] (NestingScope.init 0I 0I) p match ret with | None -> false | Some _ -> true @@ -901,7 +937,7 @@ let hasUperEncodeFunction (encFunc : UPerFunction option) = | None -> false | Some fnc -> let p = {CallerScope.modName = ""; arg = Selection.valueEmptyPath "dummy"} - match fnc.funcBody p with + match fnc.funcBody (NestingScope.init 0I 0I) p with | None -> false | Some _ -> true diff --git a/CommonTypes/AbstractMacros.fs b/CommonTypes/AbstractMacros.fs index eade7f43f..1cb6c1d8c 100644 --- a/CommonTypes/AbstractMacros.fs +++ b/CommonTypes/AbstractMacros.fs @@ -309,7 +309,7 @@ Generated by the C stg macros with the following command abstract member InternalItem_string_with_alpha : p:string -> sErrCode:string -> td:FE_StringTypeDefinition -> i:string -> nLastItemIndex:BigInteger -> arrnAlphabetAsciiCodes:seq -> nAlphabetLength:BigInteger -> nCharIndexSize:BigInteger -> codec:Codec -> string; abstract member InternalItem_string_no_alpha : p:string -> sErrCode:string -> i:string -> codec:Codec -> string; abstract member IntFullyConstraint : p:string -> nMin:BigInteger -> nMax:BigInteger -> nBits:BigInteger -> sSsuffix:string -> sErrCode:string -> codec:Codec -> string; - abstract member IntFullyConstraintPos : p:string -> nMin:BigInteger -> nMax:BigInteger -> nBits:BigInteger -> sSsuffix:string -> sErrCode:string -> codec:Codec -> string; + abstract member IntFullyConstraintPos : p:string -> nMin:BigInteger -> nMax:BigInteger -> nBits:BigInteger -> sSsuffix:string -> sErrCode:string -> soRangeAssert:string option -> codec:Codec -> string; abstract member IntUnconstrained : p:string -> sErrCode:string -> bCoverageIgnore:bool -> codec:Codec -> string; abstract member IntUnconstrainedMax : p:string -> nMax:BigInteger -> soCheckExp:string option -> sErrCode:string -> codec:Codec -> string; abstract member IntSemiConstraint : p:string -> nMin:BigInteger -> sErrCode:string -> codec:Codec -> string; @@ -325,17 +325,17 @@ Generated by the C stg macros with the following command abstract member Enumerated_item : p:string -> sName:string -> nIndex:BigInteger -> nLastItemIndex:BigInteger -> codec:Codec -> string; abstract member Enumerated : p:string -> td:FE_EnumeratedTypeDefinition -> arrsItem:seq -> nMin:BigInteger -> nMax:BigInteger -> nBits:BigInteger -> sErrCode:string -> nLastItemIndex:BigInteger -> sFirstItemName:string -> codec:Codec -> string; abstract member choice_child : p:string -> sAcc:string -> sChildID:string -> nChildIndex:BigInteger -> nIndexSizeInBits:BigInteger -> nLastItemIndex:BigInteger -> sChildContent:string -> sChildName:string -> sChildTypeDef:string -> sChoiceTypeName:string -> sChildInitExpr:string -> bIsSequence:bool -> bIsEnum:bool -> codec:Codec -> string; - abstract member choice : p:string -> sAcc:string -> arrsChildren:seq -> nLastItemIndex:BigInteger -> sChoiceIndexName:string -> sErrCode:string -> td:FE_ChoiceTypeDefinition -> nIndexSizeInBits:BigInteger -> codec:Codec -> string; + abstract member choice : p:string -> sAcc:string -> arrsChildren:seq -> nLastItemIndex:BigInteger -> sChoiceIndexName:string -> sErrCode:string -> td:FE_ChoiceTypeDefinition -> nIndexSizeInBits:BigInteger -> bIntroSnap:bool -> codec:Codec -> string; abstract member sequence_presence_bit : p:string -> sAcc:string -> sChName:string -> soExistVar:string option -> sErrCode:string -> codec:Codec -> string; abstract member sequence_presence_bit_fix : p:string -> sAcc:string -> sChName:string -> soExistVar:string option -> sErrCode:string -> sVal:string -> codec:Codec -> string; abstract member sequence_mandatory_child : sChName:string -> sChildContent:string -> codec:Codec -> string; abstract member sequence_optional_child : p:string -> sAcc:string -> sChName:string -> sChildContent:string -> soExistVar:string option -> soChildExpr:string option -> sChildTypedef:string -> codec:Codec -> string; abstract member sequence_default_child : p:string -> sAcc:string -> sChName:string -> sChildContent:string -> soExistVar:string option -> soChildExpr:string option -> sChildTypedef:string -> sInitWithDefaultValue:string -> codec:Codec -> string; abstract member sequence_build : p:string -> sTypeDefName:string -> arrsChildren:seq -> string; - abstract member str_FixedSize : p:string -> sTasName:string -> i:string -> sInternalItem:string -> nFixedSize:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> soInitExpr:string option -> codec:Codec -> string; + abstract member str_FixedSize : p:string -> sTasName:string -> i:string -> sInternalItem:string -> nFixedSize:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> soInitExpr:string option -> bIntroSnap:bool -> soPreSerde:string option -> soPostSerde:string option -> soPostInc:string option -> soInvariant:string option -> codec:Codec -> string; abstract member str_VarSize : p:string -> sTasName:string -> i:string -> sInternalItem:string -> nSizeMin:BigInteger -> nSizeMax:BigInteger -> nSizeInBits:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> soInitExpr:string option -> codec:Codec -> string; abstract member seqOf_FixedSize : p:string -> sTasName:string -> i:string -> sInternalItem:string -> nFixedSize:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> sChildInitExpr:string -> codec:Codec -> string; - abstract member seqOf_VarSize : p:string -> sAcc:string -> sTasName:string -> i:string -> sInternalItem:string -> nSizeMin:BigInteger -> nSizeMax:BigInteger -> nSizeInBits:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> sChildInitExpr:string -> sErrCode:string -> codec:Codec -> string; + abstract member seqOf_VarSize : p:string -> sAcc:string -> sTasName:string -> i:string -> sInternalItem:string -> nSizeMin:BigInteger -> nSizeMax:BigInteger -> nSizeInBits:BigInteger -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> nAlignSize:BigInteger -> sChildInitExpr:string -> sErrCode:string -> nAbsOffset:BigInteger -> nRemainingMinBits:BigInteger -> nLevel:BigInteger -> nIx:BigInteger -> nOffset:BigInteger -> bIntroSnap:bool -> soPreSerde:string option -> soPostSerde:string option -> soPostInc:string option -> soInvariant:string option -> codec:Codec -> string; abstract member octet_FixedSize : sTypeDefName:string -> p:string -> sAcc:string -> nFixedSize:BigInteger -> codec:Codec -> string; abstract member octet_VarSize : sTypeDefName:string -> p:string -> sAcc:string -> nSizeMin:BigInteger -> nSizeMax:BigInteger -> nSizeInBits:BigInteger -> sErrCode:string -> codec:Codec -> string; abstract member bitString_FixSize : sTypeDefName:string -> p:string -> sAcc:string -> nFixedSize:BigInteger -> sErrCode:string -> codec:Codec -> string; @@ -364,7 +364,7 @@ Generated by the C stg macros with the following command abstract member EmitAcnParameter : sName:string -> sType:string -> string; abstract member EmitTypeAssignment_primitive_def : sVarName:string -> sStar:string -> sFuncName:string -> sTypeDefName:string -> arrsErrcodes:seq -> bEmptyEncodingSpace:bool -> nMaxBytesInACN:BigInteger -> nMaxBitsInACN:BigInteger -> arrsAcnPrms:seq -> soSparkAnnotations:string option -> codec:Codec -> string; abstract member EmitTypeAssignment_primitive : sVarName:string -> sStar:string -> sFuncName:string -> soIValidFuncName:string option -> sTypeDefName:string -> arrsLocalVariables:seq -> sContent:string -> soSparkAnnotations:string option -> sInitialExp:string -> arrsAcnPrms:seq -> arrsAcnParamNames:seq -> bEmptyEncodingSpace:bool -> bBsIsUnreferenced:bool -> bVarNameIsUnreferenced:bool -> soInitFuncName:string option -> arrsAnnots:seq -> arrsPrecond:seq -> soPostcond:string option -> codec:Codec -> string; - abstract member alignToNext : sMainBody:string -> sAlignmentValue:string -> nAlignmentValue:BigInteger -> codec:Codec -> string; + abstract member alignToNext : sMainBody:string -> sAlignmentValue:string -> nAlignmentValue:BigInteger -> nAbsOffset:BigInteger -> nRemainingMinBits:BigInteger -> nLevel:BigInteger -> nIx:BigInteger -> nOffset:BigInteger -> codec:Codec -> string; abstract member PositiveInteger_ConstSize : p:string -> sSsuffix:string -> sErrCode:string -> nFixedSize:BigInteger -> soMF:string option -> soMFM:string option -> nUperMin:BigInteger -> nUperMax:BigInteger -> codec:Codec -> string; abstract member PositiveInteger_ConstSize_8 : p:string -> sSsuffix:string -> sErrCode:string -> soMF:string option -> soMFM:string option -> nUperMin:BigInteger -> nUperMax:BigInteger -> codec:Codec -> string; abstract member PositiveInteger_ConstSize_big_endian_16 : p:string -> sSsuffix:string -> sErrCode:string -> soMF:string option -> soMFM:string option -> nUperMin:BigInteger -> nUperMax:BigInteger -> codec:Codec -> string; @@ -408,11 +408,11 @@ Generated by the C stg macros with the following command abstract member Acn_String_Ascii_Internal_Field_Determinant : p:string -> sErrCode:string -> nAsn1Max:BigInteger -> nAsn1Min:BigInteger -> nInternalLengthDeterminantSizeInBits:BigInteger -> codec:Codec -> string; abstract member Acn_String_CharIndex_FixSize : p:string -> sErrCode:string -> nAsn1Max:BigInteger -> arrnAlphabetAsciiCodes:seq -> nCharSetSize:BigInteger -> td:FE_StringTypeDefinition -> nCharSize:BigInteger -> codec:Codec -> string; abstract member Acn_String_CharIndex_External_Field_Determinant : p:string -> sErrCode:string -> nAsn1Max:BigInteger -> arrnAlphabetAsciiCodes:seq -> nCharSetSize:BigInteger -> sExtFld:string -> td:FE_StringTypeDefinition -> nCharSize:BigInteger -> codec:Codec -> string; - abstract member Acn_IA5String_CharIndex_External_Field_Determinant : p:string -> sErrCode:string -> nAsn1Max:BigInteger -> sExtFld:string -> td:FE_StringTypeDefinition -> nCharSize:BigInteger -> codec:Codec -> string; + abstract member Acn_IA5String_CharIndex_External_Field_Determinant : p:string -> sErrCode:string -> nAsn1Max:BigInteger -> sExtFld:string -> td:FE_StringTypeDefinition -> nCharSize:BigInteger -> nRemainingBits:BigInteger -> codec:Codec -> string; abstract member oct_external_field : sTypedefName:string -> p:string -> sAcc:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> codec:Codec -> string; abstract member oct_external_field_fix_size : sTypedefName:string -> p:string -> sAcc:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> codec:Codec -> string; - abstract member sqf_external_field : sTypeDefName:string -> p:string -> sAcc:string -> i:string -> sInternalItem:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> sChildInitExpr:string -> codec:Codec -> string; - abstract member sqf_external_field_fix_size : sTypeDefName:string -> p:string -> sAcc:string -> i:string -> sInternalItem:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> sChildInitExpr:string -> codec:Codec -> string; + abstract member sqf_external_field : sTypeDefName:string -> p:string -> sAcc:string -> i:string -> sInternalItem:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> sChildInitExpr:string -> bIntroSnap:bool -> soPreSerde:string option -> soPostSerde:string option -> soPostInc:string option -> soInvariant:string option -> codec:Codec -> string; + abstract member sqf_external_field_fix_size : sTypeDefName:string -> p:string -> sAcc:string -> i:string -> sInternalItem:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> bIsUnsigned:bool -> nAlignSize:BigInteger -> sErrCode:string -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> sChildInitExpr:string -> bIntroSnap:bool -> soPreSerde:string option -> soPostSerde:string option -> soPostInc:string option -> soInvariant:string option -> codec:Codec -> string; abstract member oct_sqf_null_terminated : p:string -> sAcc:string -> i:string -> sInternalItem:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> arruNullBytes:seq -> nBitPatternLength:BigInteger -> sErrCode:string -> nIntItemMinSize:BigInteger -> nIntItemMaxSize:BigInteger -> codec:Codec -> string; abstract member bit_string_external_field : sTypeDefName:string -> p:string -> sErrCode:string -> sAcc:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> codec:Codec -> string; abstract member bit_string_external_field_fixed_size : sTypeDefName:string -> p:string -> sErrCode:string -> sAcc:string -> noSizeMin:BigInteger option -> nSizeMax:BigInteger -> sExtFld:string -> codec:Codec -> string; diff --git a/CommonTypes/CommonTypes.fs b/CommonTypes/CommonTypes.fs index 5f343997f..2e712fbed 100644 --- a/CommonTypes/CommonTypes.fs +++ b/CommonTypes/CommonTypes.fs @@ -278,15 +278,15 @@ let someTests () = (* let getDateTimeFromAsn1TimeStringValue timeClass (str:StringLoc) = try - let dt = + let dt = match timeClass with - |Asn1LocalTime _ -> DateTime.ParseExact(str.Value, "HH:mm:ss.FFF", CultureInfo.InvariantCulture) + |Asn1LocalTime _ -> DateTime.ParseExact(str.Value, "HH:mm:ss.FFF", CultureInfo.InvariantCulture) |Asn1UtcTime _ -> DateTime.Parse(str.Value) (*.ToUniversalTime ()*) - |Asn1LocalTimeWithTimeZone _ -> DateTime.ParseExact(str.Value, "HH:mm:ss.FFFK", CultureInfo.InvariantCulture) - |Asn1Date -> DateTime.ParseExact(str.Value, "yyyy-MM-dd", CultureInfo.InvariantCulture) - |Asn1Date_LocalTime _ -> DateTime.ParseExact(str.Value, "yyyy-MM-dd'T'HH:mm:ss.FFF", CultureInfo.InvariantCulture) + |Asn1LocalTimeWithTimeZone _ -> DateTime.ParseExact(str.Value, "HH:mm:ss.FFFK", CultureInfo.InvariantCulture) + |Asn1Date -> DateTime.ParseExact(str.Value, "yyyy-MM-dd", CultureInfo.InvariantCulture) + |Asn1Date_LocalTime _ -> DateTime.ParseExact(str.Value, "yyyy-MM-dd'T'HH:mm:ss.FFF", CultureInfo.InvariantCulture) |Asn1Date_UtcTime _ -> DateTime.Parse(str.Value) (*.ToUniversalTime ()*) - |Asn1Date_LocalTimeWithTimeZone _ -> DateTime.ParseExact(str.Value, "yyyy-MM-dd'T'HH:mm:ss.FFFK", CultureInfo.InvariantCulture) + |Asn1Date_LocalTimeWithTimeZone _ -> DateTime.ParseExact(str.Value, "yyyy-MM-dd'T'HH:mm:ss.FFFK", CultureInfo.InvariantCulture) {DateTimeLoc.Value = dt; Location = str.Location} with | :? System.FormatException as e -> raise(SemanticError(str.Location, "Invalid TIME VALUE")) @@ -311,7 +311,7 @@ type ProgrammingLanguage = |C |Scala |Ada - with + with static member AllLanguages = [C; Scala; Ada] type Codec = @@ -485,9 +485,17 @@ type ReferenceToType with match path with | (MD modName)::(TA tasName)::[] -> Some ({TypeAssignmentInfo.modName = modName; tasName=tasName}) | _ -> None + + member this.topLevelTas = + match this with + | ReferenceToType path -> + match path with + | (MD modName) :: (TA tasName) :: _ -> Some {TypeAssignmentInfo.modName = modName; tasName=tasName} + | _ -> None + member this.AcnAbsPath = match this with - | ReferenceToType path -> path |> List.map (fun i -> i.StrValue) + | ReferenceToType path -> path |> List.map (fun i -> i.StrValue) //member this.getSeqChildId (childName:string) = // match this with // | ReferenceToType path -> ReferenceToType (path@[SEQ_CHILD childName]) @@ -506,12 +514,12 @@ type ReferenceToType with //member this.appendLongChildId (childRelativePath:string list) = // match this with - // | ReferenceToType path -> - // let newTail = - // childRelativePath |> + // | ReferenceToType path -> + // let newTail = + // childRelativePath |> // List.map(fun s ->SEQ_CHILD s) // ReferenceToType (path@newTail) - member this.beginsWith (md:string) (ts:string)= + member this.beginsWith (md:string) (ts:string)= match this with | ReferenceToType((MD mdName)::(TA tasName)::[]) -> mdName = md && tasName = ts | _ -> false diff --git a/CommonTypes/FsUtils.fs b/CommonTypes/FsUtils.fs index 29aa9e94b..b63df6e83 100644 --- a/CommonTypes/FsUtils.fs +++ b/CommonTypes/FsUtils.fs @@ -367,7 +367,29 @@ module List = let last lst = lst |> List.rev |> List.head - + let rec initial (xs: 'a list): 'a list = + match xs with + | [] -> failwith "init of an empty list" + | _ :: [] -> [] + | x :: xs -> x :: (initial xs) + + // 1, 2, 3, 4 -> (1, 2), (2, 3), (3, 4) + let rep2 (xs: 'a list): ('a * 'a) list = + assert (xs.Length >= 2) + let pre, rest = List.splitAt 2 xs + List.fold (fun acc x -> acc @ [(snd (List.last acc), x)]) [(pre.[0], pre.[1])] rest + + let foldBackWith (f: 'a -> 's -> 's) (init: 'a -> 's) (xs: 'a list): 's = + assert (not xs.IsEmpty) + List.foldBack f xs.Tail (init xs.Head) + + let skipLast (n: int) (lst: 'a list): 'a list = + let upto = lst.Length - n + let rec go (cnt: int) (lst: 'a list): 'a list = + match lst with + | x :: xs when cnt < upto -> x :: go (cnt + 1) xs + | _ -> [] + go 0 lst let rec keepDuplicates_private lst fnc = match lst with diff --git a/FrontEndAst/AcnCreateFromAntlr.fs b/FrontEndAst/AcnCreateFromAntlr.fs index 1ff258fdc..8995ecfdf 100644 --- a/FrontEndAst/AcnCreateFromAntlr.fs +++ b/FrontEndAst/AcnCreateFromAntlr.fs @@ -307,7 +307,7 @@ let private mergeReal (asn1: Asn1Ast.AstRoot) (loc: SrcLoc) (acnErrLoc: SrcLoc o let private mergeObjectIdentifier (asn1: Asn1Ast.AstRoot) (relativeId: bool) (loc: SrcLoc) (acnErrLoc: SrcLoc option) (props: GenericAcnProperty list) cons withcons (tdarg: GetTypeDefinition_arg) (us: Asn1AcnMergeState) = let acnErrLoc0 = match acnErrLoc with Some a -> a | None -> loc let getRtlTypeName (l:ProgrammingLanguage) = (asn1.args.getBasicLang l).getObjectIdentifierRtlTypeName relativeId - + //check for invalid properties props |> Seq.iter(fun pr -> raise(SemanticError(acnErrLoc0, "Acn property cannot be applied to OBJECT IDENTIFIER types"))) @@ -423,9 +423,9 @@ let private mergeStringType (asn1: Asn1Ast.AstRoot) (t: Asn1Ast.Asn1Type option) (l,itm), ns) us lanDefs |> Map.ofList, us1 - {StringType.acnProperties = acnProperties; cons = cons; withcons = withcons; minSize=minSize; maxSize =maxSize; - uperMaxSizeInBits = uperMaxSizeInBits; uperMinSizeInBits=uperMinSizeInBits; uperCharSet=uperCharSet; - acnEncodingClass = acnEncodingClass; acnMinSizeInBits=acnMinSizeInBits; + {StringType.acnProperties = acnProperties; cons = cons; withcons = withcons; minSize=minSize; maxSize =maxSize; + uperMaxSizeInBits = uperMaxSizeInBits; uperMinSizeInBits=uperMinSizeInBits; uperCharSet=uperCharSet; + acnEncodingClass = acnEncodingClass; acnMinSizeInBits=acnMinSizeInBits; acnMaxSizeInBits = acnMaxSizeInBits;isNumeric=isNumeric; typeDef=typeDef}, us1 let private mergeOctetStringType (asn1: Asn1Ast.AstRoot) (loc: SrcLoc) (acnErrLoc: SrcLoc option) (props: GenericAcnProperty list) cons withcons (tdarg: GetTypeDefinition_arg) (us: Asn1AcnMergeState) = @@ -542,7 +542,7 @@ let private mergeBooleanType (args: CommandLineSettings) (acnErrLoc: SrcLoc opti {Boolean.acnProperties = acnProperties; cons = cons; withcons = withcons;uperMaxSizeInBits = 1I; uperMinSizeInBits=1I; acnMinSizeInBits=acnMinSizeInBits; acnMaxSizeInBits = acnMaxSizeInBits; typeDef=typeDef; defaultInitVal="false"}, us1 -let private mergeEnumerated (asn1: Asn1Ast.AstRoot) (items: Asn1Ast.NamedItem list) (originalLocation: SrcLoc option, loc: SrcLoc) +let private mergeEnumerated (asn1: Asn1Ast.AstRoot) (items: Asn1Ast.NamedItem list) (originalLocation: SrcLoc option, loc: SrcLoc) (acnErrLoc: SrcLoc option) (acnType: AcnTypeEncodingSpec option) (props: GenericAcnProperty list) cons withcons (tdarg: EnmStrGetTypeDefinition_arg) (us: Asn1AcnMergeState) = let loc = match originalLocation with @@ -775,8 +775,8 @@ let rec private mapAcnParamTypeToAcnAcnInsertedType (asn1:Asn1Ast.AstRoot) (acn: let checkIntHasEnoughSpace asn1Min asn1Max = checkIntHasEnoughSpace acnEncodingClass acnProperties.mappingFunction.IsSome acnErrLoc asn1Min asn1Max let intClass = getIntEncodingClassByUperRange asn1.args uperRange - AcnInteger ({AcnInteger.acnProperties=acnProperties; acnAlignment=acnAlignment; acnEncodingClass = acnEncodingClass; - Location = acnErrLoc; acnMinSizeInBits=acnMinSizeInBits; acnMaxSizeInBits = acnMaxSizeInBits; cons=[]; withcons=[];isUnsigned=isUnsigned; + AcnInteger ({AcnInteger.acnProperties=acnProperties; acnAlignment=acnAlignment; acnEncodingClass = acnEncodingClass; + Location = acnErrLoc; acnMinSizeInBits=acnMinSizeInBits; acnMaxSizeInBits = acnMaxSizeInBits; cons=[]; withcons=[];isUnsigned=isUnsigned; uperRange= uperRange; intClass=intClass; checkIntHasEnoughSpace=checkIntHasEnoughSpace; inheritInfo=None; defaultValue="0"}), us | AcnPrmBoolean acnErrLoc -> @@ -1041,7 +1041,7 @@ let rec private mergeType (asn1:Asn1Ast.AstRoot) (acn:AcnAst) (m:Asn1Ast.Asn1Mo let newKind = {SequenceOf.child=newChType; acnProperties = acnProperties; cons = cons; withcons = wcons;minSize=minSize; maxSize =maxSize; uperMaxSizeInBits = uperMaxSizeInBits; uperMinSizeInBits=uperMinSizeInBits; acnEncodingClass = acnEncodingClass; acnMinSizeInBits = acnMinSizeInBits; acnMaxSizeInBits=acnMaxSizeInBits; typeDef=typeDef} SequenceOf newKind, us2 - | Asn1Ast.Sequence children -> + | Asn1Ast.Sequence children -> let childrenNameConstraints = allCons |> List.choose(fun c -> match c with Asn1Ast.WithComponentsConstraint (_,w) -> Some w| _ -> None) |> List.collect id let myVisibleConstraints = refTypeCons@t.Constraints //|> List.choose(fun c -> match c with Asn1Ast.WithComponentsConstraint _ -> None | _ -> Some c) let myNonVisibleConstraints = withCons //|> List.choose(fun c -> match c with Asn1Ast.WithComponentsConstraint _ -> None | _ -> Some c) @@ -1133,7 +1133,7 @@ let rec private mergeType (asn1:Asn1Ast.AstRoot) (acn:AcnAst) (m:Asn1Ast.Asn1Mo | Some AlwaysAbsent | Some (Optional _) | Some AlwaysPresent -> true - + match cc with | None -> let newChild, us1 = mergeType asn1 acn m c.Type (curPath@[SEQ_CHILD (c.Name.Value, isOptional)]) (typeDefPath@[SEQ_CHILD (c.Name.Value, isOptional)]) (enmItemTypeDefPath@[SEQ_CHILD (c.Name.Value, isOptional)]) None None [] childWithCons [] [] None None us diff --git a/FrontEndAst/Asn1AcnAst.fs b/FrontEndAst/Asn1AcnAst.fs index 96384fc40..0bb6e7d6b 100644 --- a/FrontEndAst/Asn1AcnAst.fs +++ b/FrontEndAst/Asn1AcnAst.fs @@ -351,6 +351,14 @@ type StringAcnEncodingClass = | Acn_Enc_String_Ascii_Null_Terminated of BigInteger*(byte list) //char size in bits, byte = the null character | Acn_Enc_String_Ascii_External_Field_Determinant of BigInteger*RelativePath //char size in bits, encode ascii, size is provided by an external length determinant | Acn_Enc_String_CharIndex_External_Field_Determinant of BigInteger*RelativePath //char size in bits, encode char index, size is provided by an external length determinant +with + member this.charSizeInBits: bigint = + match this with + | Acn_Enc_String_uPER c + | Acn_Enc_String_uPER_Ascii c + | Acn_Enc_String_Ascii_Null_Terminated (c, _) + | Acn_Enc_String_Ascii_External_Field_Determinant (c, _) + | Acn_Enc_String_CharIndex_External_Field_Determinant (c, _) -> c type SizeableAcnEncodingClass = //| SZ_EC_uPER @@ -619,6 +627,13 @@ with | AcnNullType a -> a.acnProperties.savePosition | AcnReferenceToEnumerated a -> false | AcnReferenceToIA5String a -> false + member this.acnMaxSizeInBits = + match this with + | AcnInteger a -> a.acnMaxSizeInBits + | AcnBoolean a -> a.acnMaxSizeInBits + | AcnNullType a -> a.acnMaxSizeInBits + | AcnReferenceToEnumerated a -> a.enumerated.acnMaxSizeInBits + | AcnReferenceToIA5String a -> a.str.acnMaxSizeInBits type Asn1Type = { diff --git a/FrontEndAst/Asn1AcnAstUtilFunctions.fs b/FrontEndAst/Asn1AcnAstUtilFunctions.fs index 198e58bfb..b9ac61660 100644 --- a/FrontEndAst/Asn1AcnAstUtilFunctions.fs +++ b/FrontEndAst/Asn1AcnAstUtilFunctions.fs @@ -87,6 +87,12 @@ type Asn1Type with | ObjectIdentifier x -> x.acnMaxSizeInBits | ReferenceType x -> x.acnMaxSizeInBits + member this.maxSizeInBits (enc: Asn1Encoding): BigInteger = + match enc with + | UPER -> this.uperMaxSizeInBits + | ACN -> this.acnMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + member this.ActualType = match this.Kind with | ReferenceType t-> t.resolvedType.ActualType @@ -212,7 +218,38 @@ type AcnInsertedType with type BitString with member this.MaxOctets = int (ceil ((double this.maxSize.uper)/8.0)) +type Asn1Child with + member this.getBackendName0 l = + match l with + | CommonTypes.C -> this._c_name + | CommonTypes.Scala -> this._scala_name + | CommonTypes.Ada -> this._ada_name + + member this.acnMinSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.acnMinSizeInBits + + member this.acnMaxSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.acnMaxSizeInBits + member this.uperMinSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.uperMinSizeInBits + + member this.uperMaxSizeInBits = + match this.Optionality with + | Some(AlwaysAbsent) -> 0I + | _ -> this.Type.uperMaxSizeInBits + + member this.maxSizeInBits (enc: Asn1Encoding): BigInteger = + match enc with + | UPER -> this.uperMaxSizeInBits + | ACN -> this.acnMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") type SeqChildInfo with member this.Name = @@ -222,22 +259,12 @@ type SeqChildInfo with member this.acnMinSizeInBits = match this with - | Asn1Child x -> - match x.Optionality with - | None -> x.Type.acnMinSizeInBits - | Some(AlwaysAbsent) -> 0I - | Some(AlwaysPresent) -> x.Type.acnMinSizeInBits - | Some(Optional o) -> x.Type.acnMinSizeInBits - | AcnChild x -> x.Type.acnMinSizeInBits + | Asn1Child x -> x.acnMinSizeInBits + | AcnChild x -> x.Type.acnMinSizeInBits member this.acnMaxSizeInBits = match this with - | Asn1Child x -> - match x.Optionality with - | None -> x.Type.acnMaxSizeInBits - | Some(AlwaysAbsent) -> 0I - | Some(AlwaysPresent) -> x.Type.acnMaxSizeInBits - | Some(Optional o) -> x.Type.acnMaxSizeInBits - | AcnChild x -> x.Type.acnMaxSizeInBits + | Asn1Child x -> x.acnMaxSizeInBits + | AcnChild x -> x.Type.acnMaxSizeInBits member this.acnAlignment = match this with | Asn1Child x -> x.Type.acnAlignment @@ -247,6 +274,14 @@ type SeqChildInfo with | Asn1Child x -> x.Optionality | AcnChild x -> None + member this.maxSizeInBits (enc: Asn1Encoding): BigInteger = + match enc with + | UPER -> + match this with + | Asn1Child x -> x.uperMaxSizeInBits + | AcnChild x -> raise (BugErrorException $"Unexpected UPER encoding for ACN child {x.Name}") + | ACN -> this.acnMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") let rec getASN1Name (t:Asn1Type) = match t.Kind with @@ -431,18 +466,6 @@ type Choice with // member this.AllCons = this.cons@this.withcons -type Asn1Child with - member this.getBackendName0 l = - match l with - | CommonTypes.C -> this._c_name - | CommonTypes.Scala -> this._scala_name - | CommonTypes.Ada -> this._ada_name - - - - - - type Asn1Value with member this.getBackendName () = "unnamed_variable" diff --git a/FrontEndAst/DAst.fs b/FrontEndAst/DAst.fs index 73decf3bd..ab2d16843 100644 --- a/FrontEndAst/DAst.fs +++ b/FrontEndAst/DAst.fs @@ -6,6 +6,7 @@ open System open System.Numerics open FsUtils open CommonTypes +open AcnGenericTypes open AbstractMacros open System.Collections.Generic @@ -306,9 +307,7 @@ type IsValidFunction = { funcName : string option // the name of the function. Valid only for TASes) func : string option // the body of the function funcDef : string option // function definition in header file - //funcExp : (CallerScope -> ValidationCodeBlock) // return a single boolean expression funcBody : CallerScope -> ValidationStatement //returns a list of validations statements - //funcBody2 : string -> string -> string //like funBody but with two arguments p and accessOper ( i.e. '->' or '.') alphaFuncs : AlphaFunc list localVariables : LocalVariable list @@ -319,6 +318,84 @@ type IsValidFunction = { } +///////////////////////////////////////////////////////////////////// + + +type IntegerSignedness = + | Positive + | TwosComplement + +type IntegerEndiannessSize = + | S16 + | S32 + | S64 +with + member this.bitSize = + match this with + | S16 -> 16 + | S32 -> 32 + | S64 -> 64 + +type IntegerEndianness = + | Byte + | Unbounded + | LittleEndian of IntegerEndiannessSize + | BigEndian of IntegerEndiannessSize + +type AcnIntegerEncodingType = { + signedness: IntegerSignedness + endianness: IntegerEndianness +} + +type AcnRealEncodingType = + | BigEndian32 + | BigEndian64 + | LittleEndian32 + | LittleEndian64 + +type Asn1IntegerEncodingType = + | FullyConstrainedPositive of bigint * bigint + | FullyConstrained of bigint * bigint + | SemiConstrainedPositive of bigint + | SemiConstrained of bigint + | UnconstrainedMax of bigint + | Unconstrained + +type TypeEncodingKind = + | Asn1IntegerEncodingType of Asn1IntegerEncodingType option // None if range min = max + | Asn1RealEncodingType of Asn1AcnAst.RealClass + | AcnIntegerEncodingType of AcnIntegerEncodingType + | AcnRealEncodingType of AcnRealEncodingType + | AcnBooleanEncodingType of AcnBooleanEncoding option + | AcnNullEncodingType of PATTERN_PROP_VALUE option + | AcnStringEncodingType of Asn1AcnAst.StringAcnEncodingClass + | AcnOctetStringEncodingType of Asn1AcnAst.SizeableAcnEncodingClass + | AcnBitStringEncodingType of Asn1AcnAst.SizeableAcnEncodingClass + | SequenceOfEncodingType of TypeEncodingKind * Asn1AcnAst.SizeableAcnEncodingClass + | SequenceEncodingType of TypeEncodingKind option list + | ChoiceEncodingType of TypeEncodingKind option list + | ReferenceEncodingType of string + | OptionEncodingType of TypeEncodingKind + | Placeholder + +///////////////////////////////////////////////////////////////////// + + +type NestingScope = { + acnOuterMaxSize: bigint + uperOuterMaxSize: bigint + nestingLevel: int + nestingIx: int + acnOffset: bigint + uperOffset: bigint + acnRelativeOffset: bigint + uperRelativeOffset: bigint + acnSiblingMaxSize: bigint option + uperSiblingMaxSize: bigint option +} with + static member init (acnOuterMaxSize: bigint) (uperOuterMaxSize: bigint): NestingScope = + {acnOuterMaxSize = acnOuterMaxSize; uperOuterMaxSize = uperOuterMaxSize; nestingLevel = 0; nestingIx = 0; acnRelativeOffset = 0I; uperRelativeOffset = 0I; acnOffset = 0I; uperOffset = 0I; acnSiblingMaxSize = None; uperSiblingMaxSize = None} + type UPERFuncBodyResult = { funcBody : string @@ -327,13 +404,14 @@ type UPERFuncBodyResult = { bValIsUnReferenced : bool bBsIsUnReferenced : bool resultExpr : string option + typeEncodingKind : TypeEncodingKind option } type UPerFunction = { funcName : string option // the name of the function func : string option // the body of the function funcDef : string option // function definition in header file - funcBody : CallerScope -> (UPERFuncBodyResult option) // returns a list of validations statements - funcBody_e : ErrorCode -> CallerScope -> (UPERFuncBodyResult option) + funcBody : NestingScope -> CallerScope -> (UPERFuncBodyResult option) // returns a list of validations statements + funcBody_e : ErrorCode -> NestingScope -> CallerScope -> (UPERFuncBodyResult option) } type AcnFuncBodyResult = { @@ -343,6 +421,7 @@ type AcnFuncBodyResult = { bValIsUnReferenced : bool bBsIsUnReferenced : bool resultExpr : string option + typeEncodingKind : TypeEncodingKind option } type XERFuncBodyResult = { @@ -382,8 +461,8 @@ type AcnFunction = { // takes as input (a) any acn arguments and (b) the field where the encoding/decoding takes place // returns a list of acn encoding statements - funcBody : State->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> ((AcnFuncBodyResult option)*State) - funcBodyAsSeqComp : State->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> string -> ((AcnFuncBodyResult option)*State) + funcBody : State->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> NestingScope -> CallerScope -> ((AcnFuncBodyResult option)*State) + funcBodyAsSeqComp : State->((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> NestingScope -> CallerScope -> string -> ((AcnFuncBodyResult option)*State) isTestVaseValid : AutomaticTestCase -> bool icd : IcdAux option (* always present in Encode, always None in Decode *) } @@ -694,7 +773,7 @@ and AcnChild = { id : ReferenceToType Type : Asn1AcnAst.AcnInsertedType typeDefinitionBodyWithinSeq : string - funcBody : CommonTypes.Codec -> ((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> CallerScope -> (AcnFuncBodyResult option) // returns a list of validations statements + funcBody : CommonTypes.Codec -> ((AcnGenericTypes.RelativePath*AcnGenericTypes.AcnParameter) list) -> NestingScope -> CallerScope -> (AcnFuncBodyResult option) // returns a list of validations statements funcUpdateStatement : AcnChildUpdateResult option // vTarget, pSrcRoot, return the update statement Comments : string array initExpression : string @@ -819,7 +898,7 @@ and ReferenceType = { } and AcnChildUpdateResult = { - updateAcnChildFnc : AcnChild -> CallerScope -> CallerScope -> string + updateAcnChildFnc : AcnChild -> NestingScope -> CallerScope -> CallerScope -> string //Given an automatic test case (which includes a map with the IDs of the involved types), this function //checks if the automatic test case contains a type which depends on this acn Child. If this is true // it returns the value of the dependency, otherwise none @@ -858,7 +937,6 @@ and Asn1Type = { unitsOfMeasure : string option } - and Asn1TypeKind = | Integer of Integer | Real of Real @@ -989,4 +1067,3 @@ type TC_Function = { parameters : TC_Param list body : TC_Statement list } - diff --git a/FrontEndAst/Language.fs b/FrontEndAst/Language.fs index 35fe59473..deb59e6a4 100644 --- a/FrontEndAst/Language.fs +++ b/FrontEndAst/Language.fs @@ -4,6 +4,7 @@ open System.Numerics open DAst open FsUtils open AbstractMacros +open Asn1AcnAstUtilFunctions type Uper_parts = { createLv : string -> LocalVariable @@ -54,6 +55,153 @@ type UncheckedAccessKind = | FullAccess // unwrap all selection, including the last one | PartialAccess // unwrap all but the last selection +type TypeInfo = { + uperMaxSizeBits: bigint + acnMaxSizeBits: bigint + typeKind: TypeEncodingKind option +} with + member this.maxSize (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnMaxSizeBits + | UPER -> this.uperMaxSizeBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + +type SequenceChildProps = { + // TODO: String not ideal, but array selection index is string anyway... + sel: string option // None for presence bits + // TODO: What about padding? + uperMaxOffset: bigint + acnMaxOffset: bigint + typeInfo: TypeInfo +} with + + member this.maxOffset (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnMaxOffset + | UPER -> this.uperMaxOffset + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + +type SequenceProofGen = { + acnOuterMaxSize: bigint + uperOuterMaxSize: bigint + nestingLevel: int + nestingIx: int + uperMaxOffset: bigint + acnMaxOffset: bigint + acnSiblingMaxSize: bigint option + uperSiblingMaxSize: bigint option + children: SequenceChildProps list +} with + + member this.siblingMaxSize (enc: Asn1Encoding): bigint option = + match enc with + | ACN -> this.acnSiblingMaxSize + | UPER -> this.uperSiblingMaxSize + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + + member this.maxSize (enc: Asn1Encoding): BigInteger = + this.children |> List.map (fun c -> c.typeInfo.maxSize enc) |> List.sum + + member this.outerMaxSize (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnOuterMaxSize + | UPER -> this.uperOuterMaxSize + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + member this.maxOffset (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnMaxOffset + | UPER -> this.uperMaxOffset + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + +type SequenceOfLike = + | SqOf of Asn1AcnAst.SequenceOf + | StrType of Asn1AcnAst.StringType +with + member this.nbElems (enc: Asn1Encoding): bigint * bigint = + let nbElemsMin, nbElemsMax = + match this with + | SqOf sqf -> sqf.minSize, sqf.maxSize + | StrType st -> st.minSize, st.maxSize + match enc with + | ACN -> nbElemsMin.acn, nbElemsMax.acn + | UPER -> nbElemsMin.uper, nbElemsMax.uper + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + + member this.minNbElems (enc: Asn1Encoding): bigint = + fst (this.nbElems enc) + + member this.maxNbElems (enc: Asn1Encoding): bigint = + snd (this.nbElems enc) + + member this.sizeInBits (enc: Asn1Encoding): bigint * bigint = + match enc, this with + | ACN, SqOf sqf -> sqf.acnMinSizeInBits, sqf.acnMaxSizeInBits + | UPER, SqOf sqf -> sqf.uperMinSizeInBits, sqf.uperMaxSizeInBits + | ACN, StrType st -> st.acnMinSizeInBits, st.acnMaxSizeInBits + | UPER, StrType st -> st.uperMinSizeInBits, st.uperMaxSizeInBits + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + + member this.minSizeInBits (enc: Asn1Encoding): bigint = + fst (this.sizeInBits enc) + + member this.maxSizeInBits (enc: Asn1Encoding): bigint = + snd (this.sizeInBits enc) + + + member this.elemSizeInBits (enc: Asn1Encoding): bigint * bigint = + match enc, this with + | ACN, SqOf sqf -> sqf.child.acnMinSizeInBits, sqf.child.acnMaxSizeInBits + | UPER, SqOf sqf -> sqf.child.uperMinSizeInBits, sqf.child.uperMaxSizeInBits + | ACN, StrType st -> st.acnEncodingClass.charSizeInBits, st.acnEncodingClass.charSizeInBits + | UPER, StrType st -> + let sz = GetNumberOfBitsForNonNegativeInteger (bigint (st.uperCharSet.Length - 1)) + sz, sz + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + + member this.minElemSizeInBits (enc: Asn1Encoding): bigint = + fst (this.elemSizeInBits enc) + + member this.maxElemSizeInBits (enc: Asn1Encoding): bigint = + snd (this.elemSizeInBits enc) + + + + member this.isFixedSize: bool = + match this with + | SqOf sqf -> sqf.isFixedSize + | StrType st -> st.isFixedSize + + +type SequenceOfLikeProofGen = { + acnOuterMaxSize: bigint + uperOuterMaxSize: bigint + nestingLevel: int + nestingIx: int + acnMaxOffset: bigint + uperMaxOffset: bigint + typeInfo: TypeInfo + sel: string + ixVariable: string +} with + member this.outerMaxSize (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnOuterMaxSize + | UPER -> this.uperOuterMaxSize + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + + member this.maxOffset (enc: Asn1Encoding): bigint = + match enc with + | ACN -> this.acnMaxOffset + | UPER -> this.uperMaxOffset + | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") + +type SequenceOfLikeProofGenResult = { + preSerde: string + postSerde: string + postInc: string + invariant: string +} + [] type ILangGeneric () = abstract member ArrayStartIndex : int @@ -175,6 +323,9 @@ type ILangGeneric () = abstract member generatePrecond: Asn1Encoding -> t: Asn1AcnAst.Asn1Type -> string list abstract member generatePostcond: Asn1Encoding -> funcNameBase: string -> p: CallerScope -> t: Asn1AcnAst.Asn1Type -> Codec -> string option + abstract member generateSequenceChildProof: Asn1Encoding -> stmts: string option list -> SequenceProofGen -> Codec -> string list + abstract member generateSequenceOfLikeProof: Asn1Encoding -> SequenceOfLike -> SequenceOfLikeProofGen -> Codec -> SequenceOfLikeProofGenResult option + abstract member generateIntFullyConstraintRangeAssert: topLevelTd: string -> CallerScope -> Codec -> string option default this.getParamType (t:Asn1AcnAst.Asn1Type) (c:Codec) : CallerScope = this.getParamTypeSuffix t "" c @@ -190,6 +341,9 @@ type ILangGeneric () = default this.generatePrecond _ _ = [] default this.generatePostcond _ _ _ _ _ = None + default this.generateSequenceChildProof _ stmts _ _ = stmts |> List.choose id + default this.generateSequenceOfLikeProof _ _ _ _ = None + default this.generateIntFullyConstraintRangeAssert _ _ _ = None //most programming languages are case sensitive default _.isCaseSensitive = true diff --git a/PUSCScalaTest/asn1-pusc-lib-asn1CompilerTestInput/.gitignore b/PUSCScalaTest/asn1-pusc-lib-asn1CompilerTestInput/.gitignore index 14c6901b1..9924965fe 100644 --- a/PUSCScalaTest/asn1-pusc-lib-asn1CompilerTestInput/.gitignore +++ b/PUSCScalaTest/asn1-pusc-lib-asn1CompilerTestInput/.gitignore @@ -1,3 +1,4 @@ +out-*/ /.build /.dist /*.pro.user diff --git a/StgAda/acn_a.stg b/StgAda/acn_a.stg index cd1cf02b8..544fd1c50 100644 --- a/StgAda/acn_a.stg +++ b/StgAda/acn_a.stg @@ -154,7 +154,7 @@ end if; MFen(soMF, soMFM, p) /*nogen*/ ::= "._encode(

)

" -alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << +alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << --align to next if (bs.Current_Bit_Pos mod ) /= 0 then bs.Current_Bit_Pos := bs.Current_Bit_Pos + ( - (bs.Current_Bit_Pos mod )); @@ -163,7 +163,7 @@ end if; >> -alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << +alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << --align to next if (bs.Current_Bit_Pos mod ) /= 0 then bs.Current_Bit_Pos := bs.Current_Bit_Pos + ( - (bs.Current_Bit_Pos mod )); @@ -752,8 +752,8 @@ result.ErrorCode := ; >> -Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= "adaasn1rtl.encoding.acn.Acn_Enc_String_CharIndex_External_Field_Determinant(bs, , ,

);" -Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= << +Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= "adaasn1rtl.encoding.acn.Acn_Enc_String_CharIndex_External_Field_Determinant(bs, , ,

);" +Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= << adaasn1rtl.encoding.acn.Acn_Dec_String_CharIndex_External_Field_Determinant(bs, , , .Asn1Int(),

, result); result.ErrorCode := ; >> @@ -799,12 +799,12 @@ end loop; -sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << >> -sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << result := .ASN1_RESULT'(Success => \<= AND \<=, ErrorCode => ); if result.Success then

.Length := Integer(); @@ -813,12 +813,12 @@ end if; >> -sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << >> -sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << result := .ASN1_RESULT'(Success => \<= AND \<=, ErrorCode => ); if result.Success then @@ -1512,4 +1512,3 @@ begin end; >> - diff --git a/StgAda/uper_a.stg b/StgAda/uper_a.stg index 8895a4e28..0225d99c3 100644 --- a/StgAda/uper_a.stg +++ b/StgAda/uper_a.stg @@ -163,8 +163,8 @@ result.ErrorCode := ; adaasn1rtl.encoding.uper.UPER_Dec_ConstraintWholeNumber(bs,

, , , , result.Success); >> -IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= "adaasn1rtl.encoding.uper.UPER_Enc_ConstraintPosWholeNumber(bs,

, , );" -IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << +IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= "adaasn1rtl.encoding.uper.UPER_Enc_ConstraintPosWholeNumber(bs,

, , );" +IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= << result.ErrorCode := ; adaasn1rtl.encoding.uper.UPER_Dec_ConstraintPosWholeNumber(bs,

, , , , result.Success); >> @@ -404,13 +404,13 @@ when => >> -choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << +choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << case

kind is end case; >> -choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << +choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << result.ErrorCode := ; adaasn1rtl.encoding.uper.UPER_Dec_ConstraintWholeNumber(bs, , 0, , , result.Success); if result.Success and \>= 0 and \<= then @@ -491,12 +491,12 @@ result.ErrorCode := ; -str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << +str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << := 1; >> -str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << +str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << --val := _Init; result := .ASN1_RESULT'(Success => True, ErrorCode => 0); := 1; @@ -595,7 +595,7 @@ result := .ASN1_RESULT'(Success => True, ErrorCode => 0); >> -seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << +seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << result.Success :=

Length >= AND

Length \<= ; result.errorCode := ; := 1; @@ -605,7 +605,7 @@ if result.Success then end if; >> -seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << +seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << adaasn1rtl.encoding.uper.UPER_Dec_ConstraintWholeNumberInt(bs, nStringLength, , , , result.Success); result.errorCode := ; := 1; @@ -967,7 +967,4 @@ if result.Success then

Length := nStringLength; end if; ->> - - - +>> \ No newline at end of file diff --git a/StgC/acn_c.stg b/StgC/acn_c.stg index a97785771..93268cf12 100644 --- a/StgC/acn_c.stg +++ b/StgC/acn_c.stg @@ -118,13 +118,13 @@ for(=0; ( \< (int)) && ret; ++) -alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << +alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << Acn_AlignTo(pBitStrm, TRUE); >> -alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << +alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << Acn_AlignTo(pBitStrm, FALSE); >> @@ -512,11 +512,11 @@ ret = Acn_Dec_String_CharIndex_External_Field_Determinant(pBitStrm, , >> -Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= << +Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= << Acn_Enc_IA5String_CharIndex_External_Field_Determinant(pBitStrm, ,

); >> -Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= << +Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= << ret = Acn_Dec_IA5String_CharIndex_External_Field_Determinant(pBitStrm, , ,

); >> @@ -549,12 +549,12 @@ if (ret) { -sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << >> -sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << ret = ((\<=) && (\<=)); if (ret) {

nCount = (int); @@ -562,12 +562,12 @@ if (ret) { } >> -sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << >> -sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << ret = ((\<=) && (\<=)); if (ret) { @@ -1233,4 +1233,3 @@ bit_string_containing_func_decode(p, sFuncName, sReqBytesForAcnEncoding, sReqBit } >> - diff --git a/StgC/isvalid_c.stg b/StgC/isvalid_c.stg index 64dec7bc9..4c62dac1e 100644 --- a/StgC/isvalid_c.stg +++ b/StgC/isvalid_c.stg @@ -373,5 +373,3 @@ BitString_equal(, ,

arr, ) objId_equal(p, sObjIdLiteral)::=<< ObjectIdentifier_equal(

, &) >> - - diff --git a/StgC/uper_c.stg b/StgC/uper_c.stg index aa882a684..a051c1a72 100644 --- a/StgC/uper_c.stg +++ b/StgC/uper_c.stg @@ -151,8 +151,8 @@ ret = BitStream_DecodeConstraintWholeNumber(pBitStrm,

, , > /*case: Positive fully constraint A:: = INTEGER (5..20) */ -IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= "BitStream_EncodeConstraintPosWholeNumber(pBitStrm,

, , );" -IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << +IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= "BitStream_EncodeConstraintPosWholeNumber(pBitStrm,

, , );" +IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= << ret = BitStream_DecodeConstraintPosWholeNumber(pBitStrm,

, , ); *pErrCode = ret ? 0 : ; >> @@ -339,7 +339,7 @@ case : break; >> -choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << +choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << switch(

kind) { }; separator="\n"> @@ -349,7 +349,7 @@ default: /*COVERAGE_IGNORE*/ } >> -choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << +choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << ret = BitStream_DecodeConstraintWholeNumber(pBitStrm, &, 0, ); *pErrCode = ret ? 0 : ; if (ret) { @@ -437,11 +437,11 @@ for(=0; ( \< (int)) && ret; ++) /* IA5String & Numeric String */ -str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << +str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << >> -str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << +str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= <<

[] = 0x0; >> @@ -471,12 +471,12 @@ seqOf_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSiz >> -seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << +seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << BitStream_EncodeConstraintWholeNumber(pBitStrm,

nCount, , ); >> -seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << +seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << ret = BitStream_DecodeConstraintWholeNumber(pBitStrm, &nCount, , ); *pErrCode = ret ? 0 : ;

nCount = (long)nCount; diff --git a/StgScala/LangGeneric_scala.fs b/StgScala/LangGeneric_scala.fs index 8b5c048f0..7af2e10cc 100644 --- a/StgScala/LangGeneric_scala.fs +++ b/StgScala/LangGeneric_scala.fs @@ -86,12 +86,6 @@ let createBitStringFunction_funcBody_c handleFragmentation (codec:CommonTypes.Co {UPERFuncBodyResult.funcBody = funcBodyContent; errCodes = [errCode]; localVariables = localVariables; bValIsUnReferenced=false; bBsIsUnReferenced=false} #endif -let maxSizeInBits (enc: Asn1Encoding) (t: Asn1AcnAst.Asn1Type): BigInteger = - match enc with - | UPER -> t.uperMaxSizeInBits - | ACN -> t.acnMaxSizeInBits - | _ -> raise (BugErrorException $"Unexpected encoding: {enc}") - let srcDirName = Path.Combine("src", "main", "scala", "asn1src") let asn1rtlDirName = Path.Combine("src", "main", "scala", "asn1scala") @@ -322,24 +316,34 @@ type LangGeneric_scala() = override this.bitStringValueToByteArray (v : BitStringValue) = FsUtils.bitStringValueToByteArray (StringLoc.ByValue v) - override this.generatePrecond (enc: Asn1Encoding) (t: Asn1AcnAst.Asn1Type) = [$"codec.validate_offset_bits({maxSizeInBits enc t})"] + // TODO: Replace with an AST when it becomes complete + override this.generatePrecond (enc: Asn1Encoding) (t: Asn1AcnAst.Asn1Type) = [$"codec.base.bitStream.validate_offset_bits({t.maxSizeInBits enc})"] + // TODO: Replace with an AST when it becomes complete override this.generatePostcond (enc: Asn1Encoding) (funcNameBase: string) (p: CallerScope) (t: Asn1AcnAst.Asn1Type) (codec: Codec) = - match codec with - | Encode -> - let res = $""" + let suffix, buf = + match codec with + | Encode -> "", "w1.base.bitStream.buf.length == w2.base.bitStream.buf.length" + | Decode -> "Mut", "w1.base.bitStream.buf == w2.base.bitStream.buf" + let res = $""" res match - case Left(_) => true - case Right(res) => + case Left{suffix}(_) => true + case Right{suffix}(res) => val w1 = old(codec) val w2 = codec - w1.bufLength() == w2.bufLength() && w2.bitIndex() <= w1.bitIndex() + {maxSizeInBits enc t} && w1.isPrefixOf(w2) && {{ - val (r1, r2) = {enc}.reader(w1, w2) - val (r2Got, resGot) = {funcNameBase}_Decode_pure(r1) - resGot == RightMut(pVal) && r2Got == r2 - }}""" - Some (res.TrimStart()) - | Decode -> Some $"codec.base.bitStream.buf == old(codec).base.bitStream.buf && codec.base.bitStream.bitIndex() <= old(codec).base.bitStream.bitIndex() + {maxSizeInBits enc t}" + {buf} && w2.base.bitStream.bitIndex <= w1.base.bitStream.bitIndex + {t.maxSizeInBits enc}""" + Some (res.TrimStart()) + + override this.generateSequenceChildProof (enc: Asn1Encoding) (stmts: string option list) (pg: SequenceProofGen) (codec: Codec): string list = + ProofGen.generateSequenceChildProof enc stmts pg codec + + override this.generateSequenceOfLikeProof (enc: Asn1Encoding) (o: SequenceOfLike) (pg: SequenceOfLikeProofGen) (codec: Codec): SequenceOfLikeProofGenResult option = + ProofGen.generateSequenceOfLikeProof enc o pg codec + + override this.generateIntFullyConstraintRangeAssert (topLevelTd: string) (p: CallerScope) (codec: Codec): string option = + match codec with + | Encode -> Some $"assert({topLevelTd}_IsConstraintValid(pVal).isRight)" // TODO: HACK: When for CHOICE, `p` gets reset to the choice variant name, so we hardcode "pVal" here... + | Decode -> None override this.uper = { diff --git a/StgScala/ProofAst.fs b/StgScala/ProofAst.fs new file mode 100644 index 000000000..0f79e2d6a --- /dev/null +++ b/StgScala/ProofAst.fs @@ -0,0 +1,512 @@ +module ProofAst + +open FsUtils +open Language +open DAst +open CommonTypes + +type CodecClass = + | BaseCodec + | AcnCodec + | UperCodec +with + member this.companionObjectName = + match this with + | BaseCodec -> "Codec" + | AcnCodec -> "ACN" + | UperCodec -> "UPER" + +type RuntimeType = + | BitStream + | CodecClass of CodecClass +with + member this.companionObjectName = + match this with + | BitStream -> "BitStream" + | CodecClass cc -> cc.companionObjectName + +type IntegerType = + | Byte + | Short + | Int + | Long + | UByte + | UShort + | UInt + | ULong + +type Type = + | IntegerType of IntegerType + | RuntimeType of RuntimeType + | TypeInfo of TypeInfo + +type Lemma = + | ValidTransitiveLemma + | ValidReflexiveLemma + | ArrayBitRangesEqReflexiveLemma + | ArrayBitRangesEqSlicedLemma + | ValidateOffsetBitsIneqLemma + | ValidateOffsetBitsWeakeningLemma + | ReadPrefixLemma of TypeEncodingKind option + +type BitStreamMethod = + | ResetAt + | BitIndex + | ValidateOffsetBits + +type BitStreamFunction = + | Invariant + +type RTFunction = + | GetBitCountUnsigned + +type Var = { + name: string + tpe: Type +} + +type Pattern = + | Wildcard of Var option + | ADTPattern of ADTPattern + +and ADTPattern = { + binder: Var option + id: string // TODO: Have something better + subPatterns: Pattern list +} + +type Expr = + | Var of Var + | Block of Expr list + | Ghost of Expr + | Locally of Expr + | AppliedLemma of AppliedLemma + | Snapshot of Expr + | Let of Let + | LetGhost of Let + | Assert of Expr + | Check of Expr + | BitStreamMethodCall of BitStreamMethodCall + | BitStreamFunctionCall of BitStreamFunctionCall + | RTFunctionCall of RTFunctionCall + | TupleSelect of Expr * int + | FieldSelect of Expr * string + | ArraySelect of Expr * Expr + | ArrayLength of Expr + | MatchExpr of MatchExpr + | And of Expr list + | SplitAnd of Expr list + | Or of Expr list + | Not of Expr + | Equals of Expr * Expr + | Mult of Expr * Expr + | Plus of Expr * Expr + | Minus of Expr * Expr + | Leq of Expr * Expr + | IntLit of IntegerType * bigint + | EncDec of string + | SelectionExpr of string // TODO: Not ideal + +and AppliedLemma = { + lemma: Lemma + args: Expr list +} + +and Let = { + bdg: Var + e: Expr + body: Expr +} + +and BitStreamMethodCall = { + method: BitStreamMethod + recv: Expr + args: Expr list +} +and BitStreamFunctionCall = { + fn: BitStreamFunction + args: Expr list +} +and RTFunctionCall = { + fn: RTFunction + args: Expr list +} +and MatchExpr = { + scrut: Expr + cases: MatchCase list +} +and MatchCase = { + pattern: Pattern + rhs: Expr +} + +let mkBlock (exprs: Expr list): Expr = + if exprs.Length = 1 then exprs.Head + else + exprs |> List.collect (fun e -> match e with Block exprs -> exprs | _ -> [e]) + |> Block + +let selBase (recv: Expr): Expr = FieldSelect (recv, "base") + +let selBitStream (recv: Expr): Expr = FieldSelect (selBase recv, "bitStream") +let selBuf (recv: Expr): Expr = FieldSelect (selBase recv, "buf") +let selBufLength (recv: Expr): Expr = ArrayLength (selBuf recv) +let selCurrentByte (recv: Expr): Expr = FieldSelect (selBitStream recv, "currentByte") +let selCurrentBit (recv: Expr): Expr = FieldSelect (selBitStream recv, "currentBit") +let callBitIndex (recv: Expr): Expr = BitStreamMethodCall { method = BitIndex; recv = selBitStream recv; args = [] } +let callInvariant (recv: Expr): Expr = BitStreamFunctionCall { fn = Invariant; args = [selCurrentBit recv; selCurrentByte recv; selBufLength recv] } +let callValidateOffsetBits (recv: Expr) (offset: Expr): Expr = BitStreamMethodCall { method = ValidateOffsetBits; recv = selBitStream recv; args = [offset] } + + +////////////////////////////////////////////////////////// + +let runtimeCodecTypeFor (enc: Asn1Encoding): CodecClass = + match enc with + | UPER -> UperCodec + | ACN -> AcnCodec + | _ -> failwith $"Unsupported: {enc}" +let lemmaOwner (lemma: Lemma): RuntimeType option = + match lemma with + | ValidateOffsetBitsIneqLemma + | ValidateOffsetBitsWeakeningLemma + | ValidTransitiveLemma + | ValidReflexiveLemma -> Some BitStream + + | ArrayBitRangesEqReflexiveLemma + | ArrayBitRangesEqSlicedLemma -> None + + | ReadPrefixLemma t -> + match t with + | Some (AcnIntegerEncodingType int) -> Some (CodecClass AcnCodec) + | Some (Asn1IntegerEncodingType _) -> Some (CodecClass BaseCodec) + | Some (AcnBooleanEncodingType None) -> Some BitStream // TODO: Check this + | None -> failwith "TODO: Implement me" + | _ -> + None // TODO: Rest + +let lemmaStr (lemma: Lemma): string = + let name = + match lemma with + | ValidTransitiveLemma -> "validTransitiveLemma" + | ValidReflexiveLemma -> "validReflexiveLemma" + | ValidateOffsetBitsIneqLemma -> "validateOffsetBitsIneqLemma" + | ValidateOffsetBitsWeakeningLemma -> "validateOffsetBitsWeakeningLemma" + | ArrayBitRangesEqReflexiveLemma -> "arrayBitRangesEqReflexiveLemma" + | ArrayBitRangesEqSlicedLemma -> "arrayBitRangesEqSlicedLemma" + | ReadPrefixLemma t -> + match t with + | None -> failwith "TODO: Implement me" + | Some (AcnBooleanEncodingType None) -> "readBitPrefixLemma" // TODO: Check this + | Some (AcnIntegerEncodingType int) -> + let sign = + match int.signedness with + | Positive -> "PositiveInteger" + | TwosComplement -> "TwosComplement" + let endian, sz = + match int.endianness with + | IntegerEndianness.Byte -> None, Some "8" + | Unbounded -> None, None + | LittleEndian sz -> Some "little_endian", Some (sz.bitSize.ToString()) + | BigEndian sz -> Some "big_endian", Some (sz.bitSize.ToString()) + ([Some "dec"; Some "Int"; Some sign; Some "ConstSize"; endian; sz; Some "prefixLemma"] |> List.choose id).StrJoin "_" + | Some (Asn1IntegerEncodingType (Some Unconstrained)) -> + "decodeUnconstrainedWholeNumber_prefixLemma" + | Some (Asn1IntegerEncodingType (Some (FullyConstrainedPositive _))) -> + "decodeConstrainedPosWholeNumber_prefixLemma" + | _ -> + "ACN.readPrefixLemma_TODO" // TODO + let owner = lemmaOwner lemma + ((owner |> Option.map (fun o -> o.companionObjectName) |> Option.toList) @ [name]).StrJoin "." + +let bsMethodCallStr (meth: BitStreamMethod): string = + match meth with + | ResetAt -> "resetAt" + | BitIndex -> "bitIndex" + | ValidateOffsetBits -> "validate_offset_bits" + +let rtFnCall (fn: RTFunction): string = + match fn with + | GetBitCountUnsigned -> "GetBitCountUnsigned" + +let bsFnCall (fn: BitStreamFunction): string = + match fn with + | Invariant -> "BitStream.invariant" + +////////////////////////////////////////////////////////// + +type PrintCtx = { + curr: Expr + parents: Expr list + lvl: int +} with + member this.inc: PrintCtx = {this with lvl = this.lvl + 1} + + member this.parent = List.tryHead this.parents + + member this.nest (e: Expr): PrintCtx = {this with curr = e; parents = this.curr :: this.parents} + +type Line = { + txt: string + lvl: int +} with + member this.inc: Line = {this with lvl = this.lvl + 1} + +let isSimpleExpr (e: Expr): bool = + match e with + | Let _ | LetGhost _ | Block _ | Assert _ -> false + | _ -> true + +// TODO: Match case? +let noBracesSub (e: Expr): Expr list = + match e with + | Let l -> [l.body] + | LetGhost l -> [l.body] + | Ghost e -> [e] + | Locally e -> [e] + | _ -> [] + +let requiresBraces (e: Expr) (within: Expr option): bool = + match within with + | _ when isSimpleExpr e -> false + | Some(Ghost _ | Locally _) -> false + | Some(within) when List.contains e (noBracesSub within) -> false + | Some(_) -> + // TODO + false + | _ -> false + +let precedence (e: Expr): int = + match e with + | Or _ -> 1 + | And _ | SplitAnd _ -> 3 + | Leq _ -> 4 + | Equals _ | Not _ -> 5 + | Plus _ | Minus _ -> 7 + | Mult _ -> 8 + | _ -> 9 + +let requiresParentheses (curr: Expr) (parent: Expr option): bool = + match curr, parent with + | (_, None) -> false + | (_, Some (Let _ | BitStreamFunctionCall _ | RTFunctionCall _ | Assert _ | Check _ | MatchExpr _)) -> false + | (_, Some (BitStreamMethodCall call)) -> not (List.contains curr call.args) + | (e1, Some (e2)) when precedence e1 > precedence e2 -> false + | _ -> true + +let joined (ctx: PrintCtx) (lines: Line list) (sep: string): Line = + if lines.IsEmpty then {lvl = ctx.lvl; txt = ""} + else {lvl = lines.Head.lvl; txt = lines.StrJoin sep} + +let prepend (ctx: PrintCtx) (prefix: string) (lines: Line list): Line list = + if lines.IsEmpty then [{lvl = ctx.lvl; txt = prefix}] + else {lvl = lines.Head.lvl; txt = $"{prefix}{lines.Head.txt}"} :: lines.Tail + +let append (ctx: PrintCtx) (suffix: string) (lines: Line list): Line list = + if lines.IsEmpty then [{lvl = ctx.lvl; txt = suffix}] + else + let lst = List.last lines + (List.initial lines) @ [{lvl = lst.lvl; txt = $"{lst.txt}{suffix}"}] + +let join (ctx: PrintCtx) (sep: string) (lhs: Line list) (rhs: Line list): Line list = + if lhs.IsEmpty && rhs.IsEmpty then [{lvl = ctx.lvl; txt = sep}] + else if lhs.IsEmpty then prepend ctx sep rhs + else if rhs.IsEmpty then append ctx sep lhs + else + let lst = List.last lhs + let middle = {lvl = lst.lvl; txt = $"{lst.txt}{sep}{rhs.Head.txt}"} + (List.skipLast 1 lhs) @ [middle] @ rhs.Tail + +let lined (liness: Line list list): Line list list = + liness |> List.collect id |> List.map (fun l -> [l]) + +let rec joinN (ctx: PrintCtx) (sep: string) (liness: Line list list): Line list = + match liness with + | [] -> [] + | lines :: [] -> lines + | fst :: rest -> + let rest = joinN ctx sep rest + join ctx sep fst rest + +// TODO: Maybe have ctx.nest here already? +let rec pp (ctx: PrintCtx) (e: Expr): Line list = + if requiresBraces e ctx.parent && ctx.parent <> Some e then + [{txt = "{"; lvl = ctx.lvl}] @ ppBody ctx.inc e @ [{txt = "}"; lvl = ctx.lvl}] + else ppBody ctx e + +and joinCallLike (ctx: PrintCtx) (prefix: Line list) (argss: Line list list) (parameterless: bool): Line list = + assert (not prefix.IsEmpty) + if argss.IsEmpty && parameterless then + prefix + else + if argss |> List.exists (fun args -> args.Length > 1) then + let args = (((List.initial argss) |> List.collect (fun args -> + if args.IsEmpty then [] + else + let last = List.last args + (List.initial args) @ [{last with txt = last.txt + ", "}] + )) @ (List.last argss)) |> List.map (fun l -> l.inc) + (join ctx "(" prefix args) @ [{lvl = ctx.lvl; txt = ")"}] + else + join ctx "(" prefix [{lvl = ctx.lvl; txt = ((List.concat argss) |> List.map (fun l -> l.txt)).StrJoin ", " + ")"}] + +and ppLet (ctx: PrintCtx) (theLet: Expr) (lt: Let) (annot: string list): Line list = + let e2 = pp (ctx.nest theLet) lt.e + let body = pp (ctx.nest theLet) lt.body + let annot = if annot.IsEmpty then "" else (annot.StrJoin " ") + " " + let prepended = (prepend ctx $"{annot}val {lt.bdg.name} = " e2) + prepended @ body + +and ppMatchExpr (ctx: PrintCtx) (mexpr: MatchExpr): Line list = + let rec ppPattern (pat: Pattern): string = + match pat with + | Wildcard None -> "_" + | Wildcard (Some var) -> var.name + | ADTPattern pat -> + let bdg = pat.binder |> Option.map (fun bdg -> $"${bdg.name} @ ") |> Option.defaultValue "" + let subpats = (pat.subPatterns |> List.map ppPattern).StrJoin ", " + $"{bdg}{pat.id}({subpats})" + + let ppMatchCase (ctx: PrintCtx) (cse: MatchCase): Line list = + let pat = {txt = $"case {ppPattern cse.pattern} =>"; lvl = ctx.lvl} + pat :: pp (ctx.inc) cse.rhs + + let ctxNested = ctx.nest (MatchExpr mexpr) + let cases = mexpr.cases |> List.collect (ppMatchCase ctxNested.inc) + let scrut = pp ctxNested mexpr.scrut + (append ctx " match {" scrut) @ cases @ [{txt = "}"; lvl = ctx.lvl}] + +and optP (ctx: PrintCtx) (ls: Line list): Line list = + if requiresParentheses ctx.curr ctx.parent then + prepend ctx "(" (append ctx ")" ls) + else ls + +and ppBody (ctx: PrintCtx) (e: Expr): Line list = + let line (str: string): Line = {txt = str; lvl = ctx.lvl} + + match e with + | Var v -> [line v.name] + | Block exprs -> + List.collect (fun e2 -> pp (ctx.nest e2) e2) exprs + + | Ghost e2 -> + [line "ghostExpr {"] @ (pp (ctx.inc.nest e2) e2) @ [line "}"] + + | Locally e2 -> + [line "locally {"] @ (pp (ctx.inc.nest e2) e2) @ [line "}"] + + | AppliedLemma app -> + let args = app.args |> List.map (fun a -> pp (ctx.nest a) a) + joinCallLike ctx [line (lemmaStr app.lemma)] args true + + | Snapshot e2 -> + joinCallLike ctx [line "snapshot"] [pp (ctx.nest e2) e2] false + + | Let lt -> ppLet ctx e lt [] + + | LetGhost lt -> ppLet ctx e lt ["@ghost"] + + | Assert pred -> + let pred = pp (ctx.nest pred) pred + joinCallLike ctx [line "assert"] [pred] false + + | Check pred -> + let pred = pp (ctx.nest pred) pred + joinCallLike ctx [line "check"] [pred] false + + | BitStreamMethodCall call -> + let recv = pp (ctx.nest call.recv) call.recv + let meth = bsMethodCallStr call.method + let args = call.args |> List.map (fun a -> pp (ctx.nest a) a) + joinCallLike ctx (append ctx $".{meth}" recv) args true + + | BitStreamFunctionCall call -> + let meth = bsFnCall call.fn + let args = call.args |> List.map (fun a -> pp (ctx.nest a) a) + joinCallLike ctx [line meth] args true + + | RTFunctionCall call -> + let meth = rtFnCall call.fn + let args = call.args |> List.map (fun a -> pp (ctx.nest a) a) + joinCallLike ctx [line meth] args true + + | TupleSelect (recv, ix) -> + let recv = pp (ctx.nest recv) recv + append ctx $"._{ix}" recv + + | FieldSelect (recv, sel) -> + let recv = pp (ctx.nest recv) recv + append ctx $".{sel}" recv + + | ArraySelect (arr, ix) -> + let recv = pp (ctx.nest arr) arr + let ix = pp (ctx.nest ix) ix + joinCallLike ctx recv [ix] false + + | ArrayLength arr -> + let arr = pp (ctx.nest arr) arr + append ctx $".length" arr + + | IntLit (tpe, i) -> + let i = i.ToString() + let str = + match tpe with + | Byte -> $"{i}.toByte" + | Short -> $"{i}.toShort" + | Int -> i + | Long -> $"{i}L" + | UByte -> $"UByte.fromRaw({i}.toByte)" + | UShort -> $"UShort.fromRaw({i}.toShort)" + | UInt -> $"UInt.fromRaw({i})" + | ULong -> $"ULong.fromRaw({i}L)" + [line str] + + | Equals (lhs, rhs) -> + let lhs = pp (ctx.nest lhs) lhs + let rhs = pp (ctx.nest rhs) rhs + optP ctx (join ctx " == " lhs rhs) + + | Leq (lhs, rhs) -> + let lhs = pp (ctx.nest lhs) lhs + let rhs = pp (ctx.nest rhs) rhs + optP ctx (join ctx " <= " lhs rhs) + + | And conjs -> + let conjs = conjs |> List.map (fun c -> pp (ctx.nest c) c) + optP ctx (joinN ctx " && " conjs) + + | SplitAnd conjs -> + let conjs = conjs |> List.map (fun c -> pp (ctx.nest c) c) + optP ctx (joinN ctx " &&& " conjs) + + | Or disjs -> + let disjs = disjs |> List.map (fun d -> pp (ctx.nest d) d) + optP ctx (joinN ctx " || " disjs) + + | Not e2 -> + let e2 = pp (ctx.nest e2) e2 + optP ctx (prepend ctx "!" e2) + + | Plus (lhs, rhs) -> + let lhs = pp (ctx.nest lhs) lhs + let rhs = pp (ctx.nest rhs) rhs + optP ctx (join ctx " + " lhs rhs) + + | Minus (lhs, rhs) -> + let lhs = pp (ctx.nest lhs) lhs + let rhs = pp (ctx.nest rhs) rhs + optP ctx (join ctx " - " lhs rhs) + + | Mult (lhs, rhs) -> + let lhs = pp (ctx.nest lhs) lhs + let rhs = pp (ctx.nest rhs) rhs + optP ctx (join ctx " * " lhs rhs) + + | MatchExpr mexpr -> ppMatchExpr ctx mexpr + + | SelectionExpr sel -> [line sel] + + | EncDec stmt -> + (stmt.Split [|'\n'|]) |> Array.toList |> List.map line + +let show (e: Expr): string = + (pp {curr = e; parents = []; lvl = 0} e |> List.map (fun line -> (String.replicate line.lvl " ") + line.txt)).StrJoin "\n" diff --git a/StgScala/ProofGen.fs b/StgScala/ProofGen.fs new file mode 100644 index 000000000..77875fe4e --- /dev/null +++ b/StgScala/ProofGen.fs @@ -0,0 +1,242 @@ +module ProofGen +open ProofAst +open DAst +open FsUtils +open CommonTypes +open Language +open Asn1AcnAst +open Asn1AcnAstUtilFunctions + +let generateTransitiveLemmaApp (snapshots: Var list) (codec: Var): Expr = + assert (snapshots.Length >= 2) + + let mkLemma (s1: Var) (s2: Var, s3: Var): Expr = + AppliedLemma {lemma = ValidTransitiveLemma; args = [selBitStream (Var s1); selBitStream (Var s2); selBitStream (Var s3)]} + + let helper (start: int): Expr list = + let s1 = snapshots.[start] + List.rep2 ((List.skip (start + 1) snapshots) @ [codec]) |> List.map (mkLemma s1) + + [0 .. snapshots.Length - 2] |> List.collect helper |> mkBlock + +let generateReadPrefixLemmaApp (snapshots: Var list) (children: TypeInfo list) (codec: Var) : Expr = + assert (children.Length = snapshots.Length) + + let rec extraArgsForType (tpe: TypeEncodingKind option): Expr list = + match tpe with + | Some (OptionEncodingType tpe) -> extraArgsForType (Some tpe) + | Some (Asn1IntegerEncodingType (Some encodingTpe)) -> + match encodingTpe with + | FullyConstrainedPositive (min, max) -> [IntLit (ULong, min); IntLit (ULong, max)] + | FullyConstrained (min, max) -> [IntLit (Long, min); IntLit (Long, max)] + | SemiConstrainedPositive min -> [IntLit (ULong, min)] + | SemiConstrained max -> [IntLit (Long, max)] + | UnconstrainedMax max -> [IntLit (Long, max)] + | Unconstrained -> [] + | _ -> [] // TODO: Rest + + let mkLemma (bs1: Var, bs2: Var, tpe: TypeInfo): Expr = + let var = {Var.name = $"{bs2.name}_reset"; tpe = bs2.tpe} + let rst = BitStreamMethodCall {method = ResetAt; recv = Var bs2; args = [Var bs1]} + let tpeNoOpt = + match tpe.typeKind with + | Some (OptionEncodingType tpe) -> Some tpe + | _ -> tpe.typeKind + let varArg, codecArg = + match lemmaOwner (ReadPrefixLemma tpeNoOpt) with + | Some (CodecClass BaseCodec) -> selBase (Var var), selBase (Var codec) + | Some BitStream -> selBitStream (Var var), selBitStream (Var codec) + | _ -> Var var, Var codec + let extraArgs = extraArgsForType tpeNoOpt + let app = AppliedLemma {lemma = ReadPrefixLemma tpeNoOpt; args = [varArg; codecArg] @ extraArgs} + Let {bdg = var; e = rst; body = app} + + List.zip3 (List.skipLast 1 snapshots) snapshots.Tail (List.skipLast 1 children) |> List.map mkLemma |> Block + +let wrapEncDecStmts (enc: Asn1Encoding) (snapshots: Var list) (cdc: Var) (oldCdc: Var) (stmts: string option list) (pg: SequenceProofGen) (codec: Codec) (rest: Expr): Expr = + let nbChildren = pg.children.Length + assert (snapshots.Length = nbChildren) + assert (stmts.Length = nbChildren) + + let rec assertionsConditions (tpe: TypeEncodingKind option): Expr option = + match tpe with + | Some (OptionEncodingType tpe) -> assertionsConditions (Some tpe) + | Some (Asn1IntegerEncodingType (Some encodingTpe)) -> + match encodingTpe with + | FullyConstrainedPositive (min, max) | FullyConstrained (min, max) -> + // TODO: The RT library does not add 1, why? + let call = RTFunctionCall {fn = GetBitCountUnsigned; args = [IntLit (ULong, max - min)]} + // TODO: Case min = max? + let nBits = if max = min then 0I else bigint (ceil ((log (double (max - min))) / (log 2.0))) + let cond = Equals (call, IntLit (Int, nBits)) + Some cond + | _ -> None + | _ -> None + + let addAssert (tpe: TypeEncodingKind option): Expr = + assertionsConditions tpe |> Option.map (fun cond -> Assert cond) + |> Option.defaultValue (mkBlock []) + + let outerMaxSize = pg.outerMaxSize enc + let thisMaxSize = pg.maxSize enc + let fstSnap = snapshots.Head + let isNested = pg.nestingLevel > 0 + assert (isNested || fstSnap = oldCdc) + + let wrap (ix: int, (snap: Var, child: SequenceChildProps, stmt: string option)) (offsetAcc: bigint, rest: Expr): bigint * Expr = + let sz = child.typeInfo.maxSize enc + //assert (thisMaxSize <= (pg.siblingMaxSize enc |> Option.defaultValue thisMaxSize)) // TODO: Somehow does not always hold with UPER? + let relativeOffset = offsetAcc - (pg.maxOffset enc) + let offsetCheckOverall = Check (Leq (callBitIndex (Var cdc), Plus ((callBitIndex (Var oldCdc)), (IntLit (Long, offsetAcc))))) + let offsetCheckNested = + if isNested then [Check (Leq (callBitIndex (Var cdc), Plus ((callBitIndex (Var fstSnap)), (IntLit (Long, relativeOffset)))))] + else [] + let bufCheck = + match codec with + | Encode -> [] + | Decode -> [Check ((Equals (selBuf (Var cdc), selBuf (Var oldCdc))))] + let offsetWidening = + match pg.siblingMaxSize enc with + | Some siblingMaxSize when ix = nbChildren - 1 && siblingMaxSize <> thisMaxSize -> + let diff = siblingMaxSize - thisMaxSize + [ + Check (Leq (callBitIndex (Var cdc), Plus ((callBitIndex (Var oldCdc)), (IntLit (Long, offsetAcc + diff))))); + Check (Leq (callBitIndex (Var cdc), Plus ((callBitIndex (Var fstSnap)), (IntLit (Long, relativeOffset + diff))))); + ] + | _ -> [] + let checks = offsetCheckOverall :: offsetCheckNested @ bufCheck @ offsetWidening + let body = + match stmt with + | Some stmt when true || ix < nbChildren - 1 -> + let lemma = AppliedLemma { + lemma = ValidateOffsetBitsIneqLemma; + args = [selBitStream (Var snap); selBitStream (Var cdc); IntLit (Long, outerMaxSize - offsetAcc + sz); IntLit (Long, sz)] } + mkBlock ((addAssert child.typeInfo.typeKind) :: [EncDec stmt; Ghost (mkBlock (lemma :: checks)); rest]) + + | Some stmt -> + mkBlock ((addAssert child.typeInfo.typeKind) :: ([EncDec stmt; Ghost (mkBlock checks); rest])) + + | _ -> mkBlock [Ghost (mkBlock checks); rest] + + (offsetAcc - sz, LetGhost {bdg = snap; e = Snapshot (Var cdc); body = body}) + + let stmts = List.zip3 snapshots pg.children stmts |> List.indexed + List.foldBack wrap stmts ((pg.maxOffset enc) + thisMaxSize, rest) |> snd + +let generateSequenceChildProof (enc: Asn1Encoding) (stmts: string option list) (pg: SequenceProofGen) (codec: Codec): string list = + if stmts.IsEmpty then [] + else + let codecTpe = runtimeCodecTypeFor enc + let cdc = {Var.name = $"codec"; tpe = RuntimeType (CodecClass codecTpe)} + let oldCdc = {Var.name = $"codec_0_1"; tpe = RuntimeType (CodecClass codecTpe)} + let snapshots = [1 .. pg.children.Length] |> List.map (fun i -> {Var.name = $"codec_{pg.nestingLevel}_{pg.nestingIx + i}"; tpe = RuntimeType (CodecClass codecTpe)}) + + let wrappedStmts = wrapEncDecStmts enc snapshots cdc oldCdc stmts pg codec + + let postCondLemmas = + let cond = Leq (callBitIndex (Var cdc), Plus ((callBitIndex (Var snapshots.Head)), (IntLit (Long, pg.outerMaxSize enc)))) + Ghost (Check cond) + let expr = wrappedStmts (mkBlock [postCondLemmas]) + let exprStr = show expr + [exprStr] + +let generateSequenceOfLikeProof (enc: Asn1Encoding) (sqf: SequenceOfLike) (pg: SequenceOfLikeProofGen) (codec: Codec): SequenceOfLikeProofGenResult option = + let nbItemsMin, nbItemsMax = sqf.nbElems enc + + let isSizeExternal = + match enc, sqf with + | UPER, _ -> true + | ACN, SqOf sqf -> + match sqf.acnEncodingClass with + | SizeableAcnEncodingClass.SZ_EC_FIXED_SIZE | SizeableAcnEncodingClass.SZ_EC_LENGTH_EMBEDDED _ -> not sqf.isFixedSize // TODO: Check if we can have SZ_EC_FIXED_SIZE with not sqf.isFixedSize (copying logic from DAstACN) + | _ -> true + | ACN, StrType str -> + true // TODO + | _ -> failwith $"Unexpected encoding: {enc}" + + let externSizeInBits = + if isSizeExternal then GetNumberOfBitsForNonNegativeInteger (nbItemsMax - nbItemsMin) + else 0I + let nbItems = + if sqf.isFixedSize then IntLit (Int, nbItemsMin) + else SelectionExpr $"{pg.sel}.nCount" // TODO: Not ideal... + let elemSz = sqf.maxElemSizeInBits enc + let elemSzExpr = IntLit (Long, elemSz) + let sqfMaxSizeInBits = sqf.maxSizeInBits enc + let remainingBits = pg.outerMaxSize enc - sqfMaxSizeInBits - pg.maxOffset enc + let remainingBitsExpr = IntLit (Long, remainingBits) + + let codecTpe = runtimeCodecTypeFor enc + let cdc = {Var.name = $"codec"; tpe = RuntimeType (CodecClass codecTpe)} + // The codec snapshot before encoding/decoding the whole SequenceOf (i.e. snapshot before entering the while loop) + let lvl = max 0 (pg.nestingLevel - 1) + let cdcSnap = {Var.name = $"codec_{lvl}_{pg.nestingIx + 1}"; tpe = RuntimeType (CodecClass codecTpe)} + // The codec snapshot before encoding/decoding one item (snapshot local to the loop, taken before enc/dec one item) + let cdcLoopSnap = {Var.name = $"codecLoop_{lvl}_{pg.nestingIx + 1}"; tpe = RuntimeType (CodecClass codecTpe)} + let ix = {name = pg.ixVariable; tpe = IntegerType Int} + let ixPlusOne = Plus (Var ix, IntLit (Int, 1I)) + + let preSerde = + LetGhost ({ + bdg = cdcLoopSnap + e = Snapshot (Var cdc) + body = Ghost (AppliedLemma { + lemma = ValidateOffsetBitsWeakeningLemma + args = [ + selBitStream (Var cdc); + Plus (remainingBitsExpr, Mult (elemSzExpr, Minus (nbItems, Var ix))) + elemSzExpr + ] + }) + }) + let postSerde = + Ghost (mkBlock [ + Check (Equals ( + Mult (elemSzExpr, Plus (Var ix, IntLit (Int, 1I))), + Plus (Mult (elemSzExpr, Var ix), elemSzExpr) + )) + Check (Leq ( + callBitIndex (Var cdc), + Plus (callBitIndex (Var cdcSnap), Plus (IntLit (Long, externSizeInBits), Mult (elemSzExpr, ixPlusOne))) + )) + AppliedLemma { + lemma = ValidateOffsetBitsIneqLemma + args = [ + selBitStream (Var cdcLoopSnap) + selBitStream (Var cdc) + Plus (remainingBitsExpr, Mult (elemSzExpr, Minus (nbItems, Var ix))) + elemSzExpr + ] + } + Check (callValidateOffsetBits (Var cdc) (Plus (remainingBitsExpr, Mult (elemSzExpr, Minus (nbItems, ixPlusOne))))) + ]) + let invariants = + let bufInv = + if codec = Encode then + Equals (selBufLength (Var cdc), selBufLength (Var cdcSnap)) + else + Equals (selBuf (Var cdc), selBuf (Var cdcSnap)) + let cdcInv = callInvariant (Var cdc) + let boundsInv = + if sqf.isFixedSize then [] + else [And [Leq (IntLit (Int, nbItemsMin), nbItems); Leq (nbItems, (IntLit (Int, nbItemsMax)))]] + let bixInv = Leq ( + callBitIndex (Var cdc), + Plus (callBitIndex (Var cdcSnap), Plus (IntLit (Long, externSizeInBits), Mult (elemSzExpr, Var ix))) + ) + let offsetInv = callValidateOffsetBits (Var cdc) (Plus (remainingBitsExpr, Mult (elemSzExpr, Minus (nbItems, Var ix)))) + [bufInv; cdcInv] @ boundsInv @ [bixInv; offsetInv] + + let postInc = + Ghost (mkBlock ( + Check (And [ + Leq (IntLit (Int, 0I), Var ix) + Leq (Var ix, nbItems) + ]) :: (invariants |> List.map Check))) + + Some { + preSerde = show preSerde + postSerde = show postSerde + postInc = show postInc + invariant = show (SplitAnd invariants) + } \ No newline at end of file diff --git a/StgScala/StgScala.fsproj b/StgScala/StgScala.fsproj index f693e772e..3179de0c2 100644 --- a/StgScala/StgScala.fsproj +++ b/StgScala/StgScala.fsproj @@ -1,12 +1,12 @@ - - + net7.0 true win-x64;linux-x64;osx-x64 - + + @@ -28,7 +28,6 @@ - @@ -71,36 +70,30 @@ PreserveNewest - - - - - - - - - - - ..\Antlr\antlr313\antlr.runtime.dll - - - ..\Antlr\antlr313\Antlr3.Runtime.dll - - - ..\Antlr\antlr313\Antlr3.Utility.dll - - - ..\Antlr\antlr313\StringTemplate.dll - - - - - - - - - - - - - + + + + + + + + + ..\Antlr\antlr313\antlr.runtime.dll + + + ..\Antlr\antlr313\Antlr3.Runtime.dll + + + ..\Antlr\antlr313\Antlr3.Utility.dll + + + ..\Antlr\antlr313\StringTemplate.dll + + + + + + + + + \ No newline at end of file diff --git a/StgScala/acn_scala.stg b/StgScala/acn_scala.stg index b14173c43..ac16bdfee 100644 --- a/StgScala/acn_scala.stg +++ b/StgScala/acn_scala.stg @@ -1,12 +1,12 @@ group scala_acn; -getStringSize(p) ::= "

.indexOf(0x00.toRawUByte)" +getStringSize(p) ::= "ULong.fromRaw(

.indexOf(0x00.toRawUByte))" getSizeableSize(p, sAcc, bIsUnsigned) ::= << -ULong.fromRaw(

nCount) // TODO acn:5 +ULong.fromRaw(

nCount) -

nCount // TODO acn:5 +

nCount >> @@ -24,14 +24,12 @@ EmitTypeAssignment_primitive_def_encode(sVarName, sStar, sFuncName, sTypeDefName >> EmitTypeAssignment_primitive_encode(sVarName, sStar, sFuncName, soIValidFuncName, sTypeDefName, arrsLocalVariables, sContent, soSparkAnnotations, sInitialExp, arrsAcnPrms, arrsAcnParamNames, bEmptyEncodingSpace, bBsIsUnreferenced, bVarNameIsUnreferenced, soInitFuncName, arrsAnnots, arrsPrecond, soPostcond) ::= << -}; separator=" "> +@opaque @inlineOnce }; separator=" "> def (@annotation.unused : , @annotation.unused codec: ACN, bCheckConstraints: Boolean): Either[ErrorCode, Int] = // acn:21 { )}; separator="\n"> }; separator="\n"> - // TODO: "return" in ensuring is non-local return for Scala --' - // if bCheckConstraints then // TODO: we must always check constraint to verify () match case Left(l) => return Left(l) case Right(_) => @@ -50,7 +48,7 @@ EmitTypeAssignment_primitive_def_decode(sVarName, sStar, sFuncName, sTypeDefName >> EmitTypeAssignment_primitive_decode(sVarName, sStar, sFuncName, soIValidFuncName, sTypeDefName, arrsLocalVariables, sContent, soSparkAnnotations, sInitialExp, arrsAcnPrms, arrsAcnParamNames, bEmptyEncodingSpace, bBsIsUnreferenced, bVarNameIsUnreferenced, soInitFuncName, arrsAnnots, arrsPrecond, soPostcond) ::= << -}; separator=" "> +@opaque @inlineOnce }; separator=" "> def (@annotation.unused codec: ACN): EitherMut[ErrorCode, ] = { )}; separator="\n"> @@ -65,7 +63,9 @@ def (@annotation.unused codec: ACN): Ei RightMut[ErrorCode, ]() -}.ensuring(_ => ) +}.ensuring { (res : EitherMut[ErrorCode, ]) => + +} @ghost @pure }; separator=" "> def _pure(codec: ACN): (ACN, EitherMut[ErrorCode, ]) = @@ -87,22 +87,51 @@ MF(soMF) ::= /*nogen*/ << loopFixedItem (i, fixedSize, sInternalItem)::= /*nogen*/ << = 0 -while \< .toInt do +(while ( \< .toInt) { + decreases(.toInt - ) += 1 +}).invariant(0 \<= && \<= .toInt) >> -alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << -codec.alignTo() +alignToNext_encode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << +locally { + @ghost val unalignedCodec = snapshot(codec) + codec.base.bitStream.alignTo() + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(unalignedCodec.base.bitStream, codec.base.bitStream, , 7L) + check(codec.base.bitStream.bitIndex \<= codec_0_1.base.bitStream.bitIndex + L + 7L) + check(codec.base.bitStream.bitIndex \<= codec__.base.bitStream.bitIndex + L + 7L) + } +} >> -alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue) ::= << -codec.alignTo() +alignToNext_decode(sMainBody, sAlignmentValue, nAlignmentValue, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset) ::= << +locally { + @ghost val unalignedCodec = snapshot(codec) + codec.base.bitStream.alignTo() + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(unalignedCodec.base.bitStream, codec.base.bitStream, , 7L) + check(codec.base.bitStream.bitIndex \<= codec_0_1.base.bitStream.bitIndex + L + 7L) + check(codec.base.bitStream.bitIndex \<= codec__.base.bitStream.bitIndex + L + 7L) + } +} >> -PositiveInteger_ConstSize_encode(p, sSsuffix, sErrCode, nFixedSize, soMF, soMFM, nUperMin, nUperMax) ::= "codec.enc_Int_PositiveInteger_ConstSize(_encode(

)

, )" +PositiveInteger_ConstSize_encode(p, sSsuffix, sErrCode, nFixedSize, soMF, soMFM, nUperMin, nUperMax) ::= << +locally { + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(v: ULong): Unit = { + require(v \<= ULong.fromRaw()) + }.ensuring(_ => GetBitCountUnsigned(v) \<= ) + bitCountLemma(_encode(

)

) + } +} +codec.enc_Int_PositiveInteger_ConstSize(_encode(

)

, ) +>> PositiveInteger_ConstSize_decode(p, sSsuffix, sErrCode, nFixedSize, soMF, soMFM, nUperMin, nUperMax) ::= << val

= codec.dec_Int_PositiveInteger_ConstSize() @@ -120,7 +149,18 @@ val

= codec.dec_Int_PositiveInteger_ConstSize_big_endian_16() >> -PositiveInteger_ConstSize_big_endian_32_encode(p, sSsuffix, sErrCode, soMF, soMFM, nUperMin, nUperMax) ::= "codec.enc_Int_PositiveInteger_ConstSize_big_endian_32(_encode(

)

)" +PositiveInteger_ConstSize_big_endian_32_encode(p, sSsuffix, sErrCode, soMF, soMFM, nUperMin, nUperMax) ::= << +locally { + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(v: ULong): Unit = { + require(v \<= ULong.fromRaw()) + }.ensuring(_ => GetBitCountUnsigned(v) \<= 4294967295L) + bitCountLemma(_encode(

)

) + } +} +codec.enc_Int_PositiveInteger_ConstSize_big_endian_32(_encode(

)

) +>> PositiveInteger_ConstSize_big_endian_32_decode(p, sSsuffix, sErrCode, soMF, soMFM, nUperMin, nUperMax) ::= << val

= codec.dec_Int_PositiveInteger_ConstSize_big_endian_32() @@ -149,7 +189,7 @@ PositiveInteger_ConstSize_little_endian_64_decode(p, sSsuffix, sErrCode, soMF, s val

= codec.dec_Int_PositiveInteger_ConstSize_little_endian_64() >> - +// TODO: Seems unused? PositiveInteger_VarSize_LengthEmbedded_encode(p, sSsuffix, sErrCode, soMF, soMFM, nUperMin) ::= "codec.enc_Int_PositiveInteger_VarSize_LengthEmbedded(_encode(

)

)" PositiveInteger_VarSize_LengthEmbedded_decode(p, sSsuffix, sErrCode, soMF, soMFM, nUperMin) ::= << val

= codec.dec_Int_PositiveInteger_VarSize_LengthEmbedded() @@ -291,7 +331,7 @@ Boolean_encode(p, ptr, bEncValIsTrue, nSize, arruTrueValueAsByteArray, arruFalse locally { val true_data: Array[UByte] = Array(.toUnsignedByte}; separator=", ">) val false_data: Array[UByte] = Array(.toUnsignedByte}; separator=", ">) - codec.appendBitsMSBFirst(if

then true_data else false_data, ) + codec.base.bitStream.appendBitsMSBFirst(if

then true_data else false_data, ) } >> @@ -317,7 +357,7 @@ Null_pattern_encode(p, arruNullValueAsByteArray, nSize, arrsBits, sErrCode, bSav locally { val tmp: Array[UByte] = Array(.toRawUByte}; separator=",">) - codec.appendBitsMSBFirst(tmp, ) + codec.base.bitStream.appendBitsMSBFirst(tmp, ) } >> @@ -428,67 +468,128 @@ val

= codec.dec_String_CharIndex_External_Field_Determinant(, allo >> -Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= << -codec.enc_IA5String_CharIndex_External_Field_Determinant(,

) +Acn_IA5String_CharIndex_External_Field_Determinant_encode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= << +locally { + val bix = codec.base.bitStream.bitIndex + codec.enc_IA5String_CharIndex_External_Field_Determinant(,

) + if codec.base.bitStream.bitIndex > bix + L * L then + return Left(461) +} >> -Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize) ::= << -val

= codec.dec_IA5String_CharIndex_External_Field_Determinant(, .toRaw) +Acn_IA5String_CharIndex_External_Field_Determinant_decode(p, sErrCode, nAsn1Max, sExtFld, td/*:FE_StringTypeDefinition*/, nCharSize, nRemainingBits) ::= << +val

= locally { + val bix = codec.base.bitStream.bitIndex + if .toRaw \< 0L then + return LeftMut(464) + val

= codec.dec_IA5String_CharIndex_External_Field_Determinant(, .toRaw) + if codec.base.bitStream.bitIndex > bix + L * L then + return LeftMut(470) +

+} >> oct_external_field_encode(sTypedefName, p, sAcc, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode) ::= << -codec.encodeOctetString_no_length(

arr,

nCount.toInt) +codec.base.encodeOctetString_no_length(

arr,

nCount.toInt) >> oct_external_field_decode(sTypedefName, p, sAcc, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode) ::= << val

= if ((ULong.fromRaw() \<= ) && ( \<= ULong.fromRaw())) then - (.toRaw.toInt, codec.decodeOctetString_no_length(.toRaw.toInt)) + (.toRaw.toInt, codec.base.decodeOctetString_no_length(.toRaw.toInt)) else return LeftMut() >> oct_external_field_fix_size_encode(sTypedefName, p, sAcc, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode) ::= << -codec.encodeOctetString_no_length(

arr, ) +codec.base.encodeOctetString_no_length(

arr, ) >> oct_external_field_fix_size_decode(sTypedefName, p, sAcc, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode) ::= << val

= if ((ULong.fromRaw() \<= ) && ( \<= ULong.fromRaw())) then - (codec.decodeOctetString_no_length()) + (codec.base.decodeOctetString_no_length()) else return LeftMut() >> -sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << - +sqf_external_field_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + + = 0 +(while( \<

.nCount.toInt) { + decreases(

.nCount.toInt - ) + + + + += 1 + +}).opaque.inline.noReturnInvariant(0 \<= && \<=

.nCount.toInt && ) >> -sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + val

= if ((ULong.fromRaw() \<= ) && ( \<= ULong.fromRaw())) then val

= (.toRaw.toInt, Array.fill(.toRaw.toInt)()) - + = 0 + (while( \<

.nCount.toInt) { + decreases(

.nCount.toInt - ) + + + + += 1 + + }).opaque.inline.noReturnInvariant(0 \<= && \<=

.nCount.toInt && )

else return LeftMut() >> -sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << - +sqf_external_field_fix_size_encode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + + = 0 +(while( \< .toInt) { + decreases(.toInt - ) + + + + += 1 + +}).opaque.inline.noReturnInvariant(0 \<= && \<= .toInt && ) >> -sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr) ::= << +sqf_external_field_fix_size_decode(sTypeDefName, p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, sExtFld, bIsUnsigned, nAlignSize, sErrCode, nIntItemMinSize, nIntItemMaxSize, sChildInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + val

= if ((ULong.fromRaw() \<= ) && ( \<= ULong.fromRaw())) then val

= (Array.fill(.toRaw.toInt)()) - + = 0 + (while( \< .toInt) { + decreases(.toInt - ) + + + + += 1 + + }).opaque.inline.noReturnInvariant(0 \<= && \<= .toInt && )

else return LeftMut() >> oct_sqf_null_terminated_encode(p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, arruNullBytes, nBitPatternLength, sErrCode, nIntItemMinSize, nIntItemMaxSize) ::= << -codec.appendBitsMSBFirst(Array({}), ) +codec.base.bitStream.appendBitsMSBFirst(Array({}), ) >> oct_sqf_null_terminated_decode(p, sAcc, i, sInternalItem, noSizeMin, nSizeMax, arruNullBytes, nBitPatternLength, sErrCode, nIntItemMinSize, nIntItemMaxSize) ::= << @@ -511,34 +612,34 @@ else if checkBitPatternPresentResult.get then >> bit_string_external_field_encode(sTypeDefName, p, sErrCode, sAcc, noSizeMin, nSizeMax, sExtFld) ::= << -codec.appendBitsMSBFirst(

arr,

nCount) +codec.base.bitStream.appendBitsMSBFirst(

arr,

nCount) >> bit_string_external_field_decode(sTypeDefName, p, sErrCode, sAcc, noSizeMin, nSizeMax, sExtFld) ::= << val

= if (\<=) && (\<=) then - (, codec.readBits()) + (, codec.base.bitStream.readBits()) else return LeftMut() >> bit_string_external_field_fixed_size_encode(sTypeDefName, p, sErrCode, sAcc, noSizeMin, nSizeMax, sExtFld) ::= << -codec.appendBitsMSBFirst(

arr, ) +codec.base.bitStream.appendBitsMSBFirst(

arr, ) >> bit_string_external_field_fixed_size_decode(sTypeDefName, p, sErrCode, sAcc, noSizeMin, nSizeMax, sExtFld) ::= << val

= if (\<=) && (\<=) then - (codec.readBits()) + (codec.base.bitStream.readBits()) else return LeftMut() >> bit_string_null_terminated_encode(sTypeDefName, p, sErrCode, sAcc, i, noSizeMin, nSizeMax, arruNullBytes, nBitPatternLength) ::= << -codec.appendBitsMSBFirst(

arr,

arr.length*8) // TODO: re-introduce nCount? -> codec.appendBitsMSBFirst(

arr,

nCount) -codec.appendBitsMSBFirst(Array({}), ) +codec.base.bitStream.appendBitsMSBFirst(

arr,

arr.length*8) // TODO: re-introduce nCount? -> codec.base.bitStream.appendBitsMSBFirst(

arr,

nCount) +codec.base.bitStream.appendBitsMSBFirst(Array({}), ) >> bit_string_null_terminated_decode(sTypeDefName, p, sErrCode, sAcc, i, noSizeMin, nSizeMax, arruNullBytes, nBitPatternLength) ::= << -val

= codec.readBits_nullterminated(Array({}), , ) match +val

= codec.base.bitStream.readBits_nullterminated(Array({}), , ) match case NoneMut() => return LeftMut() case SomeMut(arr, i) => (arr) >> @@ -564,11 +665,11 @@ ReferenceType1_decode(p, sName, bAcnEncodeFuncRequiresResult, arrsArgs, arrsLoca sequence_presence_optChild_encode(p, sAcc, sChName, soExistVar, sErrCode) ::= << -codec.appendBit(

.isDefined) +codec.base.bitStream.appendBit(

.isDefined) >> sequence_presence_optChild_decode(p, sAcc, sChName, soExistVar, sErrCode) ::= << - = codec.readBit() + = codec.base.bitStream.readBit() >> sequence_presence_optChild_pres_acn_expression_encode(p, sAcc, sChName, sAcnExpression, soExistVar, sErrCode) ::= << @@ -720,7 +821,7 @@ case => ChoiceChild_encode(p, sAcc, sChildID, nChildIndex, nIndexSizeInBits, nLastItemIndex, sChildContent, sChildName, sChildTypeDef, sChoiceTypeName, sChildInitExpr) ::= << case () => - codec.encodeConstrainedWholeNumber(, 0, ) + codec.base.encodeConstrainedWholeNumber(, 0, ) >> @@ -736,7 +837,7 @@ Choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, td/*:FE_C >> Choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, sErrCode) ::= << -val

= codec.decodeConstrainedWholeNumber(0, ) match +val

= codec.base.decodeConstrainedWholeNumber(0, ) match }; separator="\n"> case _ => return LeftMut() >> @@ -800,6 +901,8 @@ val

= match /* Updates */ SizeDependency(v, sCount, nMin, nMax, bCheckRange, sTypedefName) ::= << val = +if \< ULong.fromRaw() || \> ULong.fromRaw() then + return Left(860) >> SizeDependencyFixedSize(v, nFixedSize) ::= << @@ -915,7 +1018,7 @@ SizeDependency_oct_str_containing(p, sFuncName, sReqBytesForUperEncoding, v, bIs >> octet_string_containing_ext_field_func_encode(p, sFuncName, sReqBytesForUperEncoding, sExtField, sErrCode, soInner) ::= << -codec.encodeOctetString_no_length(arr, .toInt) +codec.base.encodeOctetString_no_length(arr, .toInt) >> octet_string_containing_ext_field_func_decode(p, sFuncName, sReqBytesForUperEncoding, sExtField, sErrCode, soInner) ::= << @@ -926,7 +1029,7 @@ octet_string_containing_ext_field_func_decode(p, sFuncName, sReqBytesForUperEnco val bitStrm: BitStream = BitStream_Init() if .toInt \<= then - codec.decodeOctetString_no_length(.toInt) match + codec.base.decodeOctetString_no_length(.toInt) match case NoneMut() => return LeftMut() case SomeMut(arr) => @@ -939,7 +1042,7 @@ octet_string_containing_ext_field_func_decode(p, sFuncName, sReqBytesForUperEnco >> bit_string_containing_ext_field_func_encode(p, sFuncName, sReqBytesForUperEncoding, sReqBitsForUperEncoding, sExtField, sErrCode) ::= << -codec.appendBitsMSBFirst(arr, .toInt) +codec.base.bitStream.appendBitsMSBFirst(arr, .toInt) >> bit_string_containing_ext_field_func_decode(p, sFuncName, sReqBytesForUperEncoding, sReqBitsForUperEncoding, sExtField, sErrCode) ::= << @@ -948,7 +1051,7 @@ bit_string_containing_ext_field_func_decode(p, sFuncName, sReqBytesForUperEncodi /* decode to a temporary bitstream */ val bitStrm: BitStream = BitStream_Init() if .toInt \<= then - codec.readBits((int)) match + codec.base.bitStream.readBits((int)) match case NoneMut() => return LeftMut() case SomeMut(arr) => @@ -975,11 +1078,11 @@ octet_string_containing_func_encode(p, sFuncName, sReqBytesForAcnEncoding, nBits int nCount = bitStrm.currentBit == 0 ? bitStrm.currentByte : (bitStrm.currentByte + 1) - codec.encodeOctetString_no_length(bitStrm.buf, nCount) + codec.base.encodeOctetString_no_length(bitStrm.buf, nCount) - codec.encodeConstrainedWholeNumber(nCount, , ) - codec.encodeOctetString_no_length(bitStrm.buf, nCount) + codec.base.encodeConstrainedWholeNumber(nCount, , ) + codec.base.encodeOctetString_no_length(bitStrm.buf, nCount) } @@ -992,20 +1095,20 @@ octet_string_containing_func_decode(p, sFuncName, sReqBytesForAcnEncoding, nBits val bitStrm: BitStream = BitStream_Init() - codec.decodeOctetString_no_length() match + codec.base.decodeOctetString_no_length() match case NoneMut() => return LeftMut(pErrCode) case SomeMut(arr) => bitStrm.buf = arr var nCount: Int = 0 - codec.decodeConstrainedWholeNumber(, ) match + codec.base.decodeConstrainedWholeNumber(, ) match case None() => return LeftMut(pErrCode) case Some(x) => nCount = x - codec.decodeOctetString_no_length(nCount.toInt) + codec.base.decodeOctetString_no_length(nCount.toInt) case NoneMut() => return LeftMut(pErrCode) case SomeMut(arr) => @@ -1030,7 +1133,7 @@ bit_string_containing_func_encode(p, sFuncName, sReqBytesForAcnEncoding, sReqBit val nCount: Int = bitStrm.currentByte*8 + bitStrm.currentBit; - codec.appendBitsMSBFirst(bitStrm.buf, nCount) + codec.base.bitStream.appendBitsMSBFirst(bitStrm.buf, nCount) codec.BitStream_EncodeConstraintWholeNumber(nCount, , ) @@ -1047,7 +1150,7 @@ bit_string_containing_func_decode(p, sFuncName, sReqBytesForAcnEncoding, sReqBit val codec: Codec = ACN(BitStream_Init()) - codec.readBits() match + codec.base.bitStream.readBits() match case NoneMut() => return LeftMut(pErrCode) case SomeMut(arr) => @@ -1059,13 +1162,13 @@ bit_string_containing_func_decode(p, sFuncName, sReqBytesForAcnEncoding, sReqBit var nCount: Int = 0 - codec.decodeConstrainedWholeNumber(, ) match + codec.base.decodeConstrainedWholeNumber(, ) match case None() => return LeftMut(pErrCode) case Some(x) => nCount = x - codec.readBits(nCount) match + codec.base.bitStream.readBits(nCount) match case NoneMut() => return LeftMut(pErrCode) case SomeMut(arr) => diff --git a/StgScala/body_scala.stg b/StgScala/body_scala.stg index 7b674bf04..7c27a8a09 100644 --- a/StgScala/body_scala.stg +++ b/StgScala/body_scala.stg @@ -9,8 +9,9 @@ Code automatically generated by asn1scc tool package asn1src import asn1scala._ -import stainless.lang._ +import stainless.lang.{ghost => ghostExpr, _} import stainless.annotation._ +import stainless.proof._ import StaticChecks._ }; separator="\n"> diff --git a/StgScala/equal_scala.stg b/StgScala/equal_scala.stg index 2477076e6..2f9333580 100644 --- a/StgScala/equal_scala.stg +++ b/StgScala/equal_scala.stg @@ -157,9 +157,11 @@ isEqual_SequenceOf_var_size(p1,p2, sAcc, i, soInnerStatement) ::= << ret = (nCount == nCount) = 0 -while ret && \< nCount do +(while (ret && \< nCount) { + decreases(nCount - ) += 1 +}).invariant(0 \<= && \<= nCount) @@ -167,9 +169,11 @@ while ret && \< nCount do isEqual_SequenceOf_fix_size(p1,p2, sAcc, i, nFixedSize, sInnerStatement) ::= << = 0 -while ret && \< do +(while (ret && \< ) { + decreases( - ) += 1 +}).invariant(0 \<= && \<= ) >> diff --git a/StgScala/header_scala.stg b/StgScala/header_scala.stg index da0fd1880..b3313cf02 100644 --- a/StgScala/header_scala.stg +++ b/StgScala/header_scala.stg @@ -143,7 +143,7 @@ Define_new_octet_string(td/*:FE_SizeableTypeDefinition*/, nMin, nMax, bFixedSize case class (var nCount: Long, arr: Array[UByte]) { - require(arr.length \<= ) + require(arr.length \<=== && 0 \<= nCount && nCount \<= arr.length) } >> @@ -166,7 +166,7 @@ Define_new_bit_string(td/*:FE_SizeableTypeDefinition*/, nMin, nMax, bFixedSize, case class (var nCount: Long, arr: Array[UByte]) { - require(arr.length \<= ) + require(arr.length \<=== && 0 \<= nCount && nCount \<= arr.length.toLong * 8L) } >> @@ -183,7 +183,7 @@ Define_new_sequence_of(td/*:FE_SizeableTypeDefinition*/, nMin, nMax, bFixedSize, case class (var nCount: Int, arr: Array[]) { - require(arr.length \<= ) + require(arr.length \<=== && 0 \<= nCount && nCount \<= arr.length) } >> diff --git a/StgScala/isvalid_scala.stg b/StgScala/isvalid_scala.stg index 54ce82342..38364aa0d 100644 --- a/StgScala/isvalid_scala.stg +++ b/StgScala/isvalid_scala.stg @@ -173,11 +173,11 @@ if ret.isRight then StatementForLoop(p, sAcc, i, bIsFixedSize, nFixedSize, sInnerStatement) ::= << = 0 -while(ret.isRight && \<

nCount) -{ +(while(ret.isRight && \<

nCount) { + decreases(

nCount - ) += 1 -} +}).invariant(0 \<= && \<=

nCount) >> @@ -188,10 +188,11 @@ def (str0: Array[UByte]): Boolean = val str = str0.toArrayRaws var valid: Boolean = true var i: Int = 0 - while ((str(i) != CHAR_0000) && valid) { + (while (i \< str.length && (str(i) != CHAR_0000) && valid) { + decreases(str.length - i) valid = valid && (); i = i + 1 - } + }).invariant(0 \<= i && i \<= str.length) valid } >> @@ -305,11 +306,11 @@ for( = 0; ret && \<

nCount< sequenceOf2(p,sAcc, i, bIsFixedSize, nFixedSize, sInnerStatement) ::= << = 0 -while( \<

nCount && ret.isRight) -{ +(while( \<

nCount && ret.isRight) { + decreases(

nCount - ) = + 1 -} +}).invariant(0 \<= && \<=

nCount) >> diff --git a/StgScala/test_cases_scala.stg b/StgScala/test_cases_scala.stg index 9843381fa..d0c4cd64b 100644 --- a/StgScala/test_cases_scala.stg +++ b/StgScala/test_cases_scala.stg @@ -62,7 +62,7 @@ Codec_Encode(sModName, sFuncName, sVal) ::= << Codec_Decode(sModName, sFuncName, sTasName, sEnc, sAmber) ::= << // test_cases_scala.stg:62 -codec.resetBitIndex() +codec.base.bitStream.resetBitIndex() // Decode value (codec) match case LeftMut(_) => return Left(2) @@ -101,9 +101,9 @@ Codec_write_bitstreamToFile() ::= << // test_cases_scala.stg:99 val file = new File(filename+".dat") val bw = new FileOutputStream(file) -val l = codec.getLength -codec.resetBitIndex() -bw.write(codec.readByteArray(l).toArrayRaws) +val l = codec.base.bitStream.getLength +codec.base.bitStream.resetBitIndex() +bw.write(codec.base.bitStream.buf.toArrayRaws, 0, l) bw.close() >> @@ -389,5 +389,3 @@ import stainless.lang._ >> - - diff --git a/StgScala/uper_scala.stg b/StgScala/uper_scala.stg index ad13b5500..fd7f50787 100644 --- a/StgScala/uper_scala.stg +++ b/StgScala/uper_scala.stg @@ -29,7 +29,7 @@ EmitTypeAssignment_def_encode(sVarName, sStar, sFuncName, sTypeDefName, arrsErrc >> EmitTypeAssignment_encode(sVarName, sStar, sFuncName, soIValidFuncName, sTypeDefName, arrsLocalVariables, sContent, soSparkAnnotations, sInitialExp, bReqBytesForEncodingIsZero, bBsIsUnreferenced, bVarNameIsUnreferenced, soInitFuncName, arrsAnnots, arrsPrecond, soPostcond) ::= << -}; separator=" "> +@opaque @inlineOnce }; separator=" "> def (@annotation.unused : , @annotation.unused codec: UPER, bCheckConstraints: Boolean): Either[ErrorCode, Int] = //uper:35 { )}; separator="\n"> @@ -54,7 +54,7 @@ EmitTypeAssignment_def_decode(sVarName, sStar, sFuncName, sTypeDefName, arrsErrc >> EmitTypeAssignment_decode(sVarName, sStar, sFuncName, soIValidFuncName, sTypeDefName, arrsLocalVariables, sContent, soSparkAnnotations, sInitialExp, bReqBytesForEncodingIsZero, bBsIsUnreferenced, bVarNameIsUnreferenced, soInitFuncName, arrsAnnots, arrsPrecond, soPostcond) ::= << -}; separator=" "> +@opaque @inlineOnce }; separator=" "> def (@annotation.unused codec: UPER): EitherMut[ErrorCode, ] = // uper:58 { )}; separator="\n"> @@ -69,7 +69,9 @@ def (@annotation.unused codec: UPER): E RightMut[ErrorCode, ](pVal) -}.ensuring(_ => ) +}.ensuring { (res : EitherMut[ErrorCode, ]) => + +} @ghost @pure }; separator=" "> def _pure(codec: UPER): (UPER, EitherMut[ErrorCode, ]) = @@ -82,7 +84,7 @@ def _pure(codec: UPER): (UPER, EitherMut[ErrorCode, ]) >> InternalItem_oct_str_encode(p, sAcc, i, sErrCode) ::=<< -if !codec.appendByte(

arr()) then +if !codec.base.bitStream.appendByte(

arr()) then Console.err.println("appendByte failed: not enough space for 1 byte") >> @@ -99,52 +101,67 @@ val allowedCharSet: Array[Byte] = Array(}; wr InternalItem_string_with_alpha_encode(p, sErrCode, td/*:FE_StringTypeDefinition*/, i, nLastItemIndex, arrnAlphabetAsciiCodes, nAlphabetLength, nCharIndexSize) ::=<< val charIndex: Int = GetCharIndex(

(), UByte.fromArrayRaws(allowedCharSet)) -codec.encodeConstrainedWholeNumber(charIndex, 0, ) +codec.base.encodeConstrainedWholeNumber(charIndex, 0, ) >> InternalItem_string_with_alpha_decode(p, sErrCode, td/*:FE_StringTypeDefinition*/, i, nLastItemIndex, arrnAlphabetAsciiCodes, nAlphabetLength, nCharIndexSize) ::=<< -

() = allowedCharSet(codec.decodeConstrainedWholeNumber(0, ).toInt).toRawUByte +

() = allowedCharSet(codec.base.decodeConstrainedWholeNumber(0, ).toInt).toRawUByte >> InternalItem_string_no_alpha_encode(p, sErrCode, i) ::=<< -codec.encodeConstrainedWholeNumber(

().toRaw, 0, 127) +codec.base.encodeConstrainedWholeNumber(

().toRaw, 0, 127) >> InternalItem_string_no_alpha_decode(p, sErrCode, i) ::=<< -

() = UByte.fromRaw(codec.decodeConstrainedWholeNumberByte(0, 127)) // uper:109 +

() = UByte.fromRaw(codec.base.decodeConstrainedWholeNumberByte(0, 127)) // uper:109 >> /* INTEGER START*/ /*case: A:: = INTEGER (-5..20) */ IntFullyConstraint_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << -codec.encodeConstrainedWholeNumber(

, , ) +codec.base.encodeConstrainedWholeNumber(

, , ) >> IntFullyConstraint_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << -val

= codec.decodeConstrainedWholeNumber(, ) // uper:122 +val

= codec.base.decodeConstrainedWholeNumber(, ) // uper:122 >> /*case: Positive fully constraint A:: = INTEGER (5..20) */ -IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << -codec.encodeConstrainedPosWholeNumber(

, .toRawULong, .toRawULong) +IntFullyConstraintPos_encode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= << +locally { + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(): Unit = ().ensuring(_ => GetBitCountUnsigned(ULong.fromRaw() - ULong.fromRaw()) == ) + bitCountLemma() + } +} + +codec.base.encodeConstrainedPosWholeNumber(

, .toRawULong, .toRawULong) >> -IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode) ::= << -val

= codec.decodeConstrainedPosWholeNumber(.toRawULong, .toRawULong) // uper:135 +IntFullyConstraintPos_decode(p, nMin, nMax, nBits, sSsuffix, sErrCode, soRangeAssert) ::= << +locally { + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(): Unit = ().ensuring(_ => GetBitCountUnsigned(ULong.fromRaw() - ULong.fromRaw()) == ) + bitCountLemma() + } +} +val

= codec.base.decodeConstrainedPosWholeNumber(ULong.fromRaw(), ULong.fromRaw()) // uper:135 >> /*case: A :: = INTEGER */ -IntUnconstrained_encode(p, sErrCode, bCoverageIgnore) ::= "codec.encodeUnconstrainedWholeNumber(

)" +IntUnconstrained_encode(p, sErrCode, bCoverageIgnore) ::= "codec.base.encodeUnconstrainedWholeNumber(

)" IntUnconstrained_decode(p, sErrCode, bCoverageIgnore) ::= << -val

= codec.decodeUnconstrainedWholeNumber() // uper:145 +val

= codec.base.decodeUnconstrainedWholeNumber() // uper:145 >> /*case: A :: = INTEGER(MIN..5) */ -IntUnconstrainedMax_encode(p, nMax, soCheckExp, sErrCode) ::= "codec.encodeUnconstrainedWholeNumber(

)" +IntUnconstrainedMax_encode(p, nMax, soCheckExp, sErrCode) ::= "codec.base.encodeUnconstrainedWholeNumber(

)" IntUnconstrainedMax_decode(p, nMax, soCheckExp, sErrCode) ::= << -if !codec.decodeUnconstrainedWholeNumber() then // TODO meth does not return a boolean value...? +if !codec.base.decodeUnconstrainedWholeNumber() then // TODO meth does not return a boolean value...? if ! then return LeftMut() @@ -153,16 +170,16 @@ if !codec.decodeUnconstrainedWholeNumber() then // TODO meth does not return a b >> /*case: A:: = INTEGER (-5..MAX) */ -IntSemiConstraint_encode(p, nMin, sErrCode) ::= "codec.encodeSemiConstrainedWholeNumber(

, )" +IntSemiConstraint_encode(p, nMin, sErrCode) ::= "codec.base.encodeSemiConstrainedWholeNumber(

, )" IntSemiConstraint_decode(p, nMin, sErrCode) ::= << -if !codec.decodeSemiConstrainedWholeNumber() then +if !codec.base.decodeSemiConstrainedWholeNumber() then return LeftMut() >> /*case: A:: = INTEGER (5..MAX) */ -IntSemiConstraintPos_encode(p, nMin, sErrCode) ::= "codec.encodeSemiConstrainedPosWholeNumber(

, )" +IntSemiConstraintPos_encode(p, nMin, sErrCode) ::= "codec.base.encodeSemiConstrainedPosWholeNumber(

, )" IntSemiConstraintPos_decode(p, nMin, sErrCode) ::= << -if !codec.decodeSemiConstrainedPosWholeNumber() then +if !codec.base.decodeSemiConstrainedPosWholeNumber() then return LeftMut() >> @@ -177,7 +194,7 @@ val

= /*case: A:: = INTEGER (5..40,...) */ IntRootExt_encode(p, nMin, sRootBaseConstraint, sIntBody, sErrCode) ::=<< -codec.appendBitZero() /* write extension bit*/ +codec.base.appendBitZero() /* write extension bit*/ >> @@ -186,7 +203,7 @@ IntRootExt_decode(p, nMin, sRootBaseConstraint, sIntBody, sErrCode) ::=<< extBit: Ref[Boolean] = Ref(false) /* read extension bit*/ - val success = codec.readBit(extBit) + val success = codec.base.bitStream.readBit(extBit) if success then if extBit == false then /* ext bit is zero ==> value is expected with root range*/ @@ -200,11 +217,11 @@ IntRootExt_decode(p, nMin, sRootBaseConstraint, sIntBody, sErrCode) ::=<< /*case: A:: = INTEGER (5..40,..., 60..70) */ IntRootExt2_encode(p, nMin, sRootBaseConstraint, sIntBody, sErrCode) ::=<< if then - codec.appendBitZero() /* write extension bit, value within root range, so ext bit is zero */ + codec.base.appendBitZero() /* write extension bit, value within root range, so ext bit is zero */ else /* value is not within root range, so ext bit is one and value is encoded as unconstrained */ - codec.appendBitOne() + codec.base.appendBitOne() >> @@ -214,16 +231,16 @@ IntRootExt2_decode(p, nMin, sRootBaseConstraint, sIntBody, sErrCode) ::=") +codec.base.bitStream.appendBit(

) >> Boolean_decode(p, sErrCode) ::= << -val

= codec.readBit() // uper:225 +val

= codec.base.bitStream.readBit() // uper:225 >> -Real_encode(p, sSuffix, sErrCode) ::= "codec.encodeReal(

)" +Real_encode(p, sSuffix, sErrCode) ::= "codec.base.encodeReal(

)" Real_decode(p, sSuffix, sErrCode) ::= << -val

= codec.decodeReal().toDouble // uper:234 +val

= codec.base.decodeReal().toDouble // uper:234 >> ObjectIdentifier_encode(p, sErrCode) ::= "codec.ObjectIdentifier_encode(

);" @@ -246,7 +263,7 @@ if !codec._decode() then Enumerated_item_encode(p, sName, nIndex, nLastItemIndex) ::= << case => - codec.encodeConstrainedWholeNumber(, 0, ) + codec.base.encodeConstrainedWholeNumber(, 0, ) >> Enumerated_item_decode(p, sName, nIndex, nLastItemIndex) ::= << case => @@ -258,7 +275,7 @@ Enumerated_encode(p, td/*:FE_EnumeratedTypeDefinition*/, arrsItem, nMin, nMax, n >> Enumerated_decode(p, td/*:FE_EnumeratedTypeDefinition*/, arrsItem, nMin, nMax, nBits, sErrCode, nLastItemIndex, sFirstItemName) ::= << -val

= codec.decodeConstrainedWholeNumber(0, ) match // uper:277 +val

= codec.base.decodeConstrainedWholeNumber(0, ) match // uper:277 case _ => return LeftMut() @@ -268,7 +285,7 @@ val

= codec.decodeConstrainedWholeNumber(0, ) match // uper: choice_child_encode(p, sAcc, sChildID, nChildIndex, nIndexSizeInBits, nLastItemIndex, sChildContent, sChildName, sChildTypeDef, sChoiceTypeName, sChildInitExpr, bIsSequence, bIsEnum) ::= << case () => - codec.encodeConstrainedWholeNumber(, 0, ) + codec.base.encodeConstrainedWholeNumber(, 0, ) >> @@ -278,13 +295,21 @@ case => () >> -choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << +choice_encode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << + +@ghost val codec_0_1 = snapshot(codec) + +

match // uper:310 }; separator="\n"> >> -choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits) ::= << -val

= codec.decodeConstrainedWholeNumber(0, ) match // uper:317 +choice_decode(p, sAcc, arrsChildren, nLastItemIndex, sChoiceIndexName, sErrCode, td/*:FE_ChoiceTypeDefinition*/, nIndexSizeInBits, bIntroSnap) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + +val

= codec.base.decodeConstrainedWholeNumber(0, ) match // uper:317 }; separator="\n"> case _ => return LeftMut() @@ -294,14 +319,14 @@ val

= codec.decodeConstrainedWholeNumber(0, ) match // uper: /* SEQUENCE START */ sequence_presence_bit_encode(p, sAcc, sChName, soExistVar, sErrCode) ::= << -codec.appendBit(

.isDefined) +codec.base.bitStream.appendBit(

.isDefined) >> sequence_presence_bit_decode(p, sAcc, sChName, soExistVar, sErrCode) ::= << -val = codec.readBit() +val = codec.base.bitStream.readBit() >> sequence_presence_bit_fix_encode(p, sAcc, sChName, soExistVar, sErrCode, sVal) ::= << -codec.appendBit() +codec.base.bitStream.appendBit() >> sequence_presence_bit_fix_decode(p, sAcc, sChName, soExistVar, sErrCode, sVal) ::= << @@ -361,37 +386,61 @@ val

= () loopFixedItem (i, fixedSize, sInternalItem)::= /*nogen*/<< = 0 -while( \< .toInt) -{ +(while( \< .toInt) { + decreases(.toInt - ) += 1 -} +}).invariant(0 \<= && \<= .toInt) >> /* IA5String & Numeric String */ -str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << - +str_FixedSize_encode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + + = 0 +(while( \< .toInt) { + decreases(.toInt - ) + + + + += 1 + +}).opaque.inline.invariant(0 \<= && \<= .toInt && ) >> -str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << +str_FixedSize_decode(p, sTasName, i, sInternalItem, nFixedSize, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + val

= - + = 0 +(while( \< .toInt) { + decreases(.toInt - ) + + + + += 1 + +}).opaque.inline.invariant(0 \<= && \<= .toInt && )

() = UByte.fromRaw(0x0) >> str_VarSize_encode(p, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << nStringLength =

.indexOf(0x00.toRawUByte) /*ret = nStringLength >= && nStringLength \<= ;*/ -codec.encodeConstrainedWholeNumber(nStringLength, , ) +codec.base.encodeConstrainedWholeNumber(nStringLength, , ) >> str_VarSize_decode(p, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, soInitExpr) ::= << val

= -nStringLength = codec.decodeConstrainedWholeNumberInt(, ) +nStringLength = codec.base.decodeConstrainedWholeNumberInt(, )

(nStringLength) = UByte.fromRaw(0) = 0 @@ -408,57 +457,105 @@ val

= (, Array.fill()()) >> -seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << -codec.encodeConstrainedWholeNumber(

nCount, , ) - +seqOf_VarSize_encode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + +locally { + @ghost val oldCodec = snapshot(codec) + codec.base.encodeConstrainedWholeNumber(

nCount, , ) + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(): Unit = ().ensuring(_ => GetBitCountUnsigned(ULong.fromRaw() - ULong.fromRaw()) == ) + bitCountLemma() + assert(codec.base.bitStream.bitIndex \<= oldCodec.base.bitStream.bitIndex + L) + BitStream.validateOffsetBitsIneqLemma(oldCodec.base.bitStream, codec.base.bitStream, , L) + check(codec.base.bitStream.bitIndex \<= codec_0_1.base.bitStream.bitIndex + L + L) + check(codec.base.bitStream.bitIndex \<= codec__.base.bitStream.bitIndex + L + L) + } +} + = 0 +(while( \<

.nCount.toInt) { + decreases(

.nCount.toInt - ) + + + + += 1 + +}).opaque.inline.noReturnInvariant(0 \<= && \<=

.nCount.toInt && ) >> -seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode) ::= << -val

_nCount = codec.decodeConstrainedWholeNumber(, ).toInt +seqOf_VarSize_decode(p, sAcc, sTasName, i, sInternalItem, nSizeMin, nSizeMax, nSizeInBits, nIntItemMinSize, nIntItemMaxSize, nAlignSize, sChildInitExpr, sErrCode, nAbsOffset, nRemainingMinBits, nLevel, nIx, nOffset, bIntroSnap, soPreSerde, soPostSerde, soPostInc, soInvariant) ::= << + +@ghost val codec_0_1 = snapshot(codec) + + +val

_nCount = locally { + @ghost val oldCodec = snapshot(codec) + val

_nCount = codec.base.decodeConstrainedWholeNumber(, ).toInt + ghostExpr { + @opaque @inlineOnce + def bitCountLemma(): Unit = ().ensuring(_ => GetBitCountUnsigned(ULong.fromRaw() - ULong.fromRaw()) == ) + bitCountLemma() + assert(codec.base.bitStream.bitIndex \<= oldCodec.base.bitStream.bitIndex + L) + BitStream.validateOffsetBitsIneqLemma(oldCodec.base.bitStream, codec.base.bitStream, , L) + check(codec.base.bitStream.bitIndex \<= codec_0_1.base.bitStream.bitIndex + L + L) + check(codec.base.bitStream.bitIndex \<= codec__.base.bitStream.bitIndex + L + L) + } +

_nCount +} val

= (

_nCount.toInt, Array.fill(

_nCount.toInt)()) = 0 - +(while( \<

_nCount.toInt) { + decreases(

_nCount.toInt - ) + + + + += 1 + +}).opaque.inline.noReturnInvariant(0 \<= && \<=

_nCount.toInt && ) >> octet_FixedSize_encode(sTypeDefName, p, sAcc, nFixedSize) ::= << -codec.encodeOctetString_no_length(

arr, .toInt) +codec.base.encodeOctetString_no_length(

arr, .toInt) >> octet_FixedSize_decode(sTypeDefName, p, sAcc, nFixedSize) ::= << -val

= (codec.decodeOctetString_no_length()) +val

= (codec.base.decodeOctetString_no_length()) >> octet_VarSize_encode(sTypeDefName, p, sAcc, nSizeMin, nSizeMax, nSizeInBits, sErrCode) ::= << -codec.encodeConstrainedWholeNumber(

nCount, , ) -codec.encodeOctetString_no_length(

arr,

nCount.toInt) +codec.base.encodeConstrainedWholeNumber(

nCount, , ) +codec.base.encodeOctetString_no_length(

arr,

nCount.toInt) >> octet_VarSize_decode(sTypeDefName, p, sAcc, nSizeMin, nSizeMax, nSizeInBits, sErrCode) ::= << // decode length -val

_nCount = codec.decodeConstrainedWholeNumber(, ) +val

_nCount = codec.base.decodeConstrainedWholeNumber(, ) // decode payload -val

_arr = codec.decodeOctetString_no_length(

_nCount.toInt) +val

_arr = codec.base.decodeOctetString_no_length(

_nCount.toInt) val

= (

_nCount,

_arr) >> /* BIT STRING*/ bitString_FixSize_encode(sTypeDefName, p, sAcc, nFixedSize, sErrCode) ::= << assert(.toInt >= 0) // overflow may happen during cast -codec.appendBitsMSBFirst(

arr, .toInt) +codec.base.bitStream.appendBitsMSBFirst(

arr, .toInt) >> bitString_FixSize_decode(sTypeDefName, p, sAcc, nFixedSize, sErrCode) ::= << -val

= (codec.readBits(.toInt)) +val

= (codec.base.bitStream.readBits(.toInt)) >> bitString_VarSize_encode(sTypeDefName, p, sAcc, nSizeMin, nSizeMax, sErrCode, nSizeInBits) ::= << -codec.encodeConstrainedWholeNumber(

nCount, , ) +codec.base.encodeConstrainedWholeNumber(

nCount, , ) >> bitString_VarSize_decode(sTypeDefName, p, sAcc, nSizeMin, nSizeMax, sErrCode, nSizeInBits) ::= << -val

_nCount = codec.decodeConstrainedWholeNumber(, ) -val

_arr = codec.readBits(

_nCount.toInt) +val

_nCount = codec.base.decodeConstrainedWholeNumber(, ) +val

_arr = codec.base.bitStream.readBits(

_nCount.toInt) val

= (

_nCount,

_arr) >> @@ -470,9 +567,9 @@ FixedSize_Fragmentation_sqf_64K_encode(p, sAcc,sCurOffset, sCurBlockSize, sBlock var = 0 while( \< ) { - codec.encodeConstrainedWholeNumber(0xC4, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(0xC4, 0, 0xFF) - codec.appendBitsMSBFirst(&

arr[/8], .toInt) + codec.base.bitStream.appendBitsMSBFirst(&

arr[/8], .toInt) val =(int) @@ -490,9 +587,9 @@ while( \< ) FixedSize_Fragmentation_sqf_small_block_encode(p, sAcc,sInternalItem, nBlockSize, sBlockId, sCurOffset, sCurBlockSize, sBLI, sRemainingItemsVar, bIsBitStringType, sErrCodeName) ::=<< //encode Block = ; -codec.encodeConstrainedWholeNumber(, 0, 0xFF) +codec.base.encodeConstrainedWholeNumber(, 0, 0xFF) -codec.appendBitsMSBFirst(&

arr[/8], .toInt) +codec.base.bitStream.appendBitsMSBFirst(&

arr[/8], .toInt) for(=(int); \< (int)( + ); ++) { @@ -506,13 +603,13 @@ for(=(int); \< (int)( + ); < FixedSize_Fragmentation_sqf_remaining_encode(p, sAcc,sInternalItem, bRemainingItemsWithinByte, nRemainingItemsVar, sCurOffset, sBLI, sRemainingItemsVar, bIsBitStringType, sErrCodeName) ::= << //encode remaining items -codec.encodeConstrainedWholeNumber(, 0, 0xFF) +codec.base.encodeConstrainedWholeNumber(, 0, 0xFF) -codec.appendBitOne() -codec.encodeConstrainedWholeNumber(, 0, 0x7FFF) +codec.base.appendBitOne() +codec.base.encodeConstrainedWholeNumber(, 0, 0x7FFF) -codec.appendBitsMSBFirst(

arr[/8], .toInt) +codec.base.bitStream.appendBitsMSBFirst(

arr[/8], .toInt) for(=(int); \< (int)( + ); ++) { @@ -535,19 +632,19 @@ while ( >= 0x4000 && \< (a { if >= 0x10000 then = 0x10000 - codec.encodeConstrainedWholeNumber(0xC4, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(0xC4, 0, 0xFF) else if >= 0xC000 then = 0xC000 - codec.encodeConstrainedWholeNumber(0xC3, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(0xC3, 0, 0xFF) else if >= 0x8000 then = 0x8000 - codec.encodeConstrainedWholeNumber(0xC2, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(0xC2, 0, 0xFF) else = 0x4000 - codec.encodeConstrainedWholeNumber(0xC1, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(0xC1, 0, 0xFF) - codec.appendBitsMSBFirst(

arr[/8], .toInt) + codec.base.bitStream.appendBitsMSBFirst(

arr[/8], .toInt) =.toInt while( \< ( + ).toInt) @@ -562,13 +659,13 @@ while ( >= 0x4000 && \< (a } if \<= 0x7F then - codec.encodeConstrainedWholeNumber(, 0, 0xFF) + codec.base.encodeConstrainedWholeNumber(, 0, 0xFF) else - codec.appendBitOne() - codec.encodeConstrainedWholeNumber(, 0, 0x7FFF) + codec.base.appendBitOne() + codec.base.encodeConstrainedWholeNumber(, 0, 0x7FFF) -codec.appendBitsMSBFirst(

arr[/8], .toInt) +codec.base.bitStream.appendBitsMSBFirst(

arr[/8], .toInt) = .toInt while( \< ( + ).toInt) @@ -586,12 +683,12 @@ FixedSize_Fragmentation_sqf_64K_decode(p, sAcc,sCurOffset, sCurBlockSize, sBlock = 0; *pErrCode = ; for( = 0; ret && \< ; ++) { - ret = codec.decodeConstrainedWholeNumber(, 0, 0xFF) + ret = codec.base.decodeConstrainedWholeNumber(, 0, 0xFF) val check = (ret == 0) && ( == 0xC4); ret = if (check) then RightMut(0) else LeftMut() if ret == 0 then - ret = codec.readBits(&

arr[/8], ).toInt + ret = codec.base.bitStream.readBits(&

arr[/8], ).toInt ret = if (ret == 0) 0 else ; @@ -612,12 +709,12 @@ for( = 0; ret && \< ; ++) { FixedSize_Fragmentation_sqf_small_block_decode(p, sAcc,sInternalItem, nBlockSize, sBlockId, sCurOffset, sCurBlockSize, sBLI, sRemainingItemsVar, bIsBitStringType, sErrCodeName) ::=<< //decode a single Block with items = ; -ret = codec.decodeConstrainedWholeNumber(, 0, 0xFF) +ret = codec.base.decodeConstrainedWholeNumber(, 0, 0xFF) val check = (ret == 0) && ( == ); ret = if (check) then RightMut(0) else LeftMut() if ret.isRight then - ret = codec.readBits(&

arr[/8], .toInt); // TODO call wrong + ret = codec.base.bitStream.readBits(&

arr[/8], .toInt); // TODO call wrong ret = if (ret == 0) then RightMut(0) else LeftMut() @@ -634,17 +731,17 @@ if ret.isRight then FixedSize_Fragmentation_sqf_remaining_decode(p, sAcc,sInternalItem, bRemainingItemsWithinByte, nRemainingItemsVar, sCurOffset, sBLI, sRemainingItemsVar, bIsBitStringType, sErrCodeName) ::= << //decode remaining items -ret = codec.decodeConstrainedWholeNumber(, 0, 0xFF) +ret = codec.base.decodeConstrainedWholeNumber(, 0, 0xFF) ret = ret && ( == ); -ret = codec.decodeConstrainedWholeNumber(, 0, 0xFFFF) +ret = codec.base.decodeConstrainedWholeNumber(, 0, 0xFFFF) ret = ret && ((0x8000 & ) > 0) && ( (0x7FFF & ) == ); if ret == 0 then - ret = codec.readBits(&

arr[/8], .toInt); // TODO call wrong + ret = codec.base.bitStream.readBits(&

arr[/8], .toInt); // TODO call wrong ret = if (ret.isRight) then RightMut(0) else LeftMut() @@ -674,7 +771,7 @@ Fragmentation_sqf_decode(p, sAcc, sInternalItem, nIntItemMaxSize, nSizeMin, nSiz = 0 - = codec.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:733 + = codec.base.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:733 while(( & 0xC0) == 0xC0) { if == 0xC4 then @@ -692,7 +789,7 @@ while(( & 0xC0) == 0xC0) { return LeftMut() - if !codec.readBits(&

arr[/8], ) then + if !codec.base.bitStream.readBits(&

arr[/8], ) then return = @@ -707,13 +804,13 @@ while(( & 0xC0) == 0xC0) { += += - = codec.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:770 + = codec.base.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:770 } if (( & 0x80) > 0) then var len2 = 0; \<\<= 8 - len2 = codec.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:780 + len2 = codec.base.decodeConstrainedWholeNumber(0, 0xFF).toInt // uper:780 |= len2; &= 0x7FFF; @@ -722,7 +819,7 @@ if ( + \<= ) then return LeftMut() -if(!codec.readBits(&

arr[/8], .toInt)) // TODO remove address of operator +if(!codec.base.bitStream.readBits(&

arr[/8], .toInt)) // TODO remove address of operator return diff --git a/asn1scala/.gitignore b/asn1scala/.gitignore index 4dce5fbf4..c05df0b1c 100644 --- a/asn1scala/.gitignore +++ b/asn1scala/.gitignore @@ -1,3 +1,4 @@ target +project .scala_objects .stainless-cache \ No newline at end of file diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm.scala index 8227d7d50..e5a12e9ba 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm.scala @@ -30,7 +30,7 @@ val MASK_POS_INT = 0x7F_FF_FF_FFL opaque type UByte = Byte object UByte { @inline def fromRaw(u: Byte): UByte = u - @inline def fromArrayRaws(arr: Array[Byte]): Array[UByte] = arr + @inline @pure def fromArrayRaws(arr: Array[Byte]): Array[UByte] = arr } extension (l: UByte) { @inline def toRaw: Byte = l @@ -79,6 +79,9 @@ object UInt { extension (l: UInt) { @inline def toRaw: Int = l @inline def <=(r: UInt): Boolean = wrappingExpr { l + Int.MinValue <= r + Int.MinValue } + @inline def <(r: UInt): Boolean = wrappingExpr { l + Int.MinValue < r + Int.MinValue } + @inline def >(r: UInt): Boolean = wrappingExpr { l + Int.MinValue > r + Int.MinValue } + @inline def >=(r: UInt): Boolean = wrappingExpr { l + Int.MinValue >= r + Int.MinValue } @inline def unsignedToLong: Long = l & MASK_INT_L @inline def toULong: ULong = l } @@ -89,18 +92,15 @@ object ULong { } extension (l: ULong) { @inline def toRaw: Long = l - @inline def toUByte: UByte = l.cutToByte - @inline def toUShort: UShort = l.cutToShort - @inline def toUInt: UInt = l.cutToInt + @inline def toUByte: UByte = wrappingExpr { l.toByte } + @inline def toUShort: UShort = wrappingExpr { l.toShort } + @inline def toUInt: UInt = wrappingExpr { l.toInt } @inline def <=(r: ULong): Boolean = wrappingExpr { l + Long.MinValue <= r + Long.MinValue } + @inline def <(r: ULong): Boolean = wrappingExpr { l + Long.MinValue < r + Long.MinValue } + @inline def >(r: ULong): Boolean = wrappingExpr { l + Long.MinValue > r + Long.MinValue } + @inline def >=(r: ULong): Boolean = wrappingExpr { l + Long.MinValue >= r + Long.MinValue } @inline def +(r: ULong): ULong = wrappingExpr { l + r } @inline def -(r: ULong): ULong = wrappingExpr { l - r } - - // @ignore - // inline def ==(r: Int): Boolean = { - // scala.compiletime.requireConst(r) - // l == r.toLong.toRawULong - // } } extension (b: Byte) { @@ -157,24 +157,6 @@ extension (l: Long) { } } -// @ignore -// inline implicit def intlit2uint(inline i: Int): UInt = { -// scala.compiletime.requireConst(i) -// UInt.fromRaw(i) -// } - -// @ignore -// inline implicit def intlit2ulong(inline i: Int): ULong = { -// scala.compiletime.requireConst(i) -// ULong.fromRaw(i.toLong) -// } - -// @ignore -// inline implicit def longlit2ulong(inline i: Long): ULong = { -// scala.compiletime.requireConst(i) -// ULong.fromRaw(i) -// } - @extern type RealNoRTL = Float type BooleanNoRTL = Boolean @@ -236,15 +218,35 @@ val ber_aux: Array[Long] = Array( // TODO: check types and if neccesary as we don't have unsigned types def int2uint(v: Long): ULong = { - v.asInstanceOf[ULong] - /*var ret: ULong = 0 + var ret: Long = 0L if v < 0 then - ret = -v - 1 - ret = ~ret + ret = wrappingExpr(-v - 1) + ret = wrappingExpr(~ret) else ret = v - ret*/ + ULong.fromRaw(ret) +} + +def onesLSBLong(nBits: Int): Long = { + require(0 <= nBits && nBits <= 64) + -1L >>> (64 - nBits) +} + +def bitLSBLong(bit: Boolean, nBits: Int): Long = { + require(0 <= nBits && nBits <= 64) + if bit then onesLSBLong(nBits) else 0L +} + +def onesMSBLong(nBits: Int): Long = { + require(0 <= nBits && nBits <= 64) + // Note: on the JVM, -1L << 64 == -1L, not 0L as sane persons would expect + if (nBits == 0) 0L else -1L << (64 - nBits) +} + +def bitMSBLong(bit: Boolean, nBits: Int): Long = { + require(0 <= nBits && nBits <= 64) + if bit then onesMSBLong(nBits) else 0L } def uint2int(v: ULong, uintSizeInBytes: Int): Long = { @@ -278,9 +280,9 @@ def GetCharIndex(ch: UByte, charSet: Array[UByte]): Int = if ch == charSet(i) then ret = i i += 1 - ).invariant(i >= 0 &&& i <= charSet.length) + ).invariant(i >= 0 &&& i <= charSet.length && ret < charSet.length && ret >= 0) ret -} +} ensuring(res => charSet.length == 0 || res >= 0 && res < charSet.length) def NullType_Initialize(): NullType = { 0 diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Bitstream.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Bitstream.scala index e678112f5..da1f9091a 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Bitstream.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Bitstream.scala @@ -9,17 +9,68 @@ import stainless.math.{wrapping => wrappingExpr, *} import StaticChecks.* object BitStream { - @pure @inline @ghost - def invariant(bs: BitStream): Boolean = { + @pure @inline + final def invariant(bs: BitStream): Boolean = { invariant(bs.currentBit, bs.currentByte, bs.buf.length) } - @pure @ghost - def invariant(currentBit: Int, currentByte: Int, buffLength: Int): Boolean = { + @pure + final def invariant(currentBit: Int, currentByte: Int, buffLength: Int): Boolean = { currentBit >= 0 && currentBit < NO_OF_BITS_IN_BYTE && currentByte >= 0 && ((currentByte < buffLength) || (currentBit == 0 && currentByte == buffLength)) } + @pure + final def remainingBits(bufLength: Long, currentByte: Long, currentBit: Long): Long = { + require(bufLength <= Int.MaxValue && currentByte <= Int.MaxValue && currentBit <= Int.MaxValue) + require(bufLength >= 0 && currentByte >= 0 && currentBit >= 0) + require(invariant(currentBit.toInt, currentByte.toInt, bufLength.toInt)) + (bufLength * NO_OF_BITS_IN_BYTE) - (currentByte * NO_OF_BITS_IN_BYTE + currentBit) + } + + @pure + final def validate_offset_bit(bufLength: Long, currentByte: Long, currentBit: Long): Boolean = { + require(bufLength <= Int.MaxValue && currentByte <= Int.MaxValue && currentBit <= Int.MaxValue) + require(bufLength >= 0 && currentByte >= 0 && currentBit >= 0) + require(invariant(currentBit.toInt, currentByte.toInt, bufLength.toInt)) + BitStream.remainingBits(bufLength, currentByte, currentBit) >= 1 + } + + @pure + final def validate_offset_bits(bufLength: Long, currentByte: Long, currentBit: Long, bits: Long = 0): Boolean = { + require(bufLength <= Int.MaxValue && currentByte <= Int.MaxValue && currentBit <= Int.MaxValue) + require(bufLength >= 0 && currentByte >= 0 && currentBit >= 0) + require(invariant(currentBit.toInt, currentByte.toInt, bufLength.toInt)) + require(bits >= 0) + BitStream.remainingBits(bufLength, currentByte, currentBit) >= bits + } + + @pure + final def validate_offset_byte(bufLength: Long, currentByte: Long, currentBit: Long): Boolean = { + require(bufLength <= Int.MaxValue && currentByte <= Int.MaxValue && currentBit <= Int.MaxValue) + require(bufLength >= 0 && currentByte >= 0 && currentBit >= 0) + require(invariant(currentBit.toInt, currentByte.toInt, bufLength.toInt)) + BitStream.remainingBits(bufLength, currentByte, currentBit) >= NO_OF_BITS_IN_BYTE + } + + @pure + final def validate_offset_bytes(bufLength: Long, currentByte: Long, currentBit: Long, bytes: Int): Boolean = { + require(bufLength <= Int.MaxValue && currentByte <= Int.MaxValue && currentBit <= Int.MaxValue) + require(bufLength >= 0 && currentByte >= 0 && currentBit >= 0) + require(invariant(currentBit.toInt, currentByte.toInt, bufLength.toInt)) + require(bytes >= 0) + bytes <= BitStream.remainingBits(bufLength, currentByte, currentBit) / NO_OF_BITS_IN_BYTE + } + + @pure + final def bitIndex(bufLength: Int, currentByte: Int, currentBit: Int): Long = { + require(invariant(currentBit, currentByte, bufLength)) + currentByte.toLong * NO_OF_BITS_IN_BYTE + currentBit.toLong + }.ensuring(res => + res == bufLength.toLong * NO_OF_BITS_IN_BYTE - BitStream.remainingBits(bufLength.toLong, currentByte.toLong, currentBit.toLong) && + 0 <= res && res <= bufLength.toLong * 8L + ) + @ghost @pure def reader(w1: BitStream, w2: BitStream): (BitStream, BitStream) = { require(w1.isPrefixOf(w2)) @@ -32,7 +83,7 @@ object BitStream { def resetAndThenMovedLemma(b1: BitStream, b2: BitStream, moveInBits: Long): Unit = { require(b1.buf.length == b2.buf.length) require(moveInBits >= 0) - require(b1.validate_offset_bits(moveInBits)) + require(BitStream.validate_offset_bits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong, moveInBits)) val b2Reset = b2.resetAt(b1) @@ -41,64 +92,131 @@ object BitStream { }.ensuring(_ => moveBitIndexPrecond(b2Reset, moveInBits)) } + @ghost @pure @opaque @inlineOnce + def eqBufAndBitIndexImpliesEq(b1: BitStream, b2: BitStream): Unit = { + require(b1.buf == b2.buf) + require(BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit ) == BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit )) + }.ensuring(_ => b1 == b2) + + @ghost @pure @opaque @inlineOnce + def validateOffsetBitsIneqLemma(b1: BitStream, b2: BitStream, b1ValidateOffsetBits: Long, advancedAtMostBits: Long): Unit = { + require(0 <= advancedAtMostBits && advancedAtMostBits <= b1ValidateOffsetBits) + require(b1.buf.length == b2.buf.length) + require(BitStream.validate_offset_bits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong, b1ValidateOffsetBits)) + require(BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit) <= BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit) + advancedAtMostBits) + + assert(BitStream.remainingBits(b1.buf.length, b1.currentByte, b1.currentBit) >= b1ValidateOffsetBits) + assert((b1.buf.length.toLong * NO_OF_BITS_IN_BYTE) - (b1.currentByte.toLong * NO_OF_BITS_IN_BYTE + b1.currentBit) >= b1ValidateOffsetBits) + assert(b2.currentByte.toLong * NO_OF_BITS_IN_BYTE + b2.currentBit <= b1.currentByte.toLong * NO_OF_BITS_IN_BYTE + b1.currentBit + advancedAtMostBits) + assert((b1.buf.length.toLong * NO_OF_BITS_IN_BYTE) - (b2.currentByte.toLong * NO_OF_BITS_IN_BYTE + b2.currentBit) >= b1ValidateOffsetBits - advancedAtMostBits) + assert(BitStream.remainingBits(b2.buf.length, b2.currentByte, b2.currentBit) >= b1ValidateOffsetBits - advancedAtMostBits) + }.ensuring(_ => BitStream.validate_offset_bits(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong, b1ValidateOffsetBits - advancedAtMostBits)) + + @ghost @pure @opaque @inlineOnce + def validateOffsetBitsWeakeningLemma(b: BitStream, origOffset: Long, newOffset: Long): Unit = { + require(0 <= newOffset && newOffset <= origOffset) + require(BitStream.validate_offset_bits(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong, origOffset)) + }.ensuring(_ => BitStream.validate_offset_bits(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong, newOffset)) + @ghost @pure @opaque @inlineOnce def validateOffsetBitsDifferenceLemma(b1: BitStream, b2: BitStream, b1ValidateOffsetBits: Long, b1b2Diff: Long): Unit = { require(b1.buf.length == b2.buf.length) require(0 <= b1ValidateOffsetBits && 0 <= b1b2Diff && b1b2Diff <= b1ValidateOffsetBits) - require(b1.validate_offset_bits(b1ValidateOffsetBits)) - require(b1.bitIndex() + b1b2Diff == b2.bitIndex()) + require(BitStream.validate_offset_bits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong, b1ValidateOffsetBits)) + require(BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit ) + b1b2Diff == BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit )) { remainingBitsBitIndexLemma(b1) - assert(b1.remainingBits == b1.buf.length.toLong * NO_OF_BITS_IN_BYTE - b1.bitIndex()) - assert(b1.bitIndex() <= b1.buf.length.toLong * NO_OF_BITS_IN_BYTE - b1ValidateOffsetBits) + assert(BitStream.remainingBits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong) == b1.buf.length.toLong * NO_OF_BITS_IN_BYTE - BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit )) + assert(BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit ) <= b1.buf.length.toLong * NO_OF_BITS_IN_BYTE - b1ValidateOffsetBits) remainingBitsBitIndexLemma(b2) - assert(b2.remainingBits == b2.buf.length.toLong * NO_OF_BITS_IN_BYTE - (b1.bitIndex() + b1b2Diff)) - assert(b2.remainingBits >= b1ValidateOffsetBits - b1b2Diff) - }.ensuring(_ => b2.validate_offset_bits(b1ValidateOffsetBits - b1b2Diff)) + assert(BitStream.remainingBits(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong) == b2.buf.length.toLong * NO_OF_BITS_IN_BYTE - (BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit ) + b1b2Diff)) + assert(BitStream.remainingBits(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong) >= b1ValidateOffsetBits - b1b2Diff) + }.ensuring(_ => BitStream.validate_offset_bits(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong, b1ValidateOffsetBits - b1b2Diff)) } @ghost @pure @opaque @inlineOnce def remainingBitsBitIndexLemma(b: BitStream): Unit = { () - }.ensuring(_ => b.remainingBits == b.buf.length.toLong * NO_OF_BITS_IN_BYTE - b.bitIndex()) + }.ensuring(_ => BitStream.remainingBits(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong) == b.buf.length.toLong * NO_OF_BITS_IN_BYTE - BitStream.bitIndex(b.buf.length, b.currentByte, b.currentBit )) @ghost @pure @opaque @inlineOnce def validateOffsetBytesContentIrrelevancyLemma(b1: BitStream, buf: Array[Byte], bytes: Int): Unit = { require(b1.buf.length == buf.length) require(bytes >= 0) - require(b1.validate_offset_bytes(bytes)) + require( BitStream.validate_offset_bytes(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong,bytes)) val b2 = BitStream(snapshot(buf), b1.currentByte, b1.currentBit) { () - }.ensuring(_ => b2.validate_offset_bytes(bytes)) + }.ensuring(_ => BitStream.validate_offset_bytes(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong,bytes)) } @ghost @pure @opaque @inlineOnce def validateOffsetBitsContentIrrelevancyLemma(b1: BitStream, buf: Array[Byte], bits: Long): Unit = { require(b1.buf.length == buf.length) require(bits >= 0) - require(b1.validate_offset_bits(bits)) + require(BitStream.validate_offset_bits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong, bits)) val b2 = BitStream(snapshot(buf), b1.currentByte, b1.currentBit) { () - }.ensuring(_ => b2.validate_offset_bits(bits)) + }.ensuring(_ => BitStream.validate_offset_bits(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong, bits)) + } + + @ghost @pure @opaque @inlineOnce + def validateOffsetBytesFromBitsLemma(b: BitStream, bits: Long, bytes: Int): Unit = { + require(0 <= bytes && bytes <= bits / 8 && 0 <= bits) + require(BitStream.validate_offset_bits(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong, bits)) + + { + () + }.ensuring(_ => BitStream.validate_offset_bytes(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong, bytes)) + } + + @ghost @pure @opaque @inlineOnce + def validateOffsetBytesFromBitIndexLemma(b1: BitStream, b2: BitStream, bits: Long, bytes: Int): Unit = { + require(b1.buf.length == b2.buf.length) + require(0 < bytes && 0 <= bits && bits <= BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit )) + require(((bits + 7) / 8).toInt <= bytes) + require(BitStream.validate_offset_bytes(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong,bytes)) + require(BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit ) == BitStream.bitIndex(b1.buf.length, b1.currentByte, b1.currentBit ) + bits) + + { + assert(bytes <= BitStream.remainingBits(b1.buf.length.toLong, b1.currentByte.toLong, b1.currentBit.toLong) / 8) + assert(bytes <= ((b1.buf.length.toLong * 8) - (b1.currentByte.toLong * 8 + b1.currentBit)) / 8) + assert(BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit ) == b2.currentByte.toLong * 8 + b2.currentBit) + assert(BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit ) - bits == b1.currentByte.toLong * 8 + b1.currentBit) + assert(bytes <= ((b2.buf.length.toLong * 8) - (b2.currentByte.toLong * 8 + b2.currentBit - bits)) / 8) + assert(bytes <= ((b2.buf.length.toLong * 8) - (b2.currentByte.toLong * 8 + b2.currentBit)) / 8 + ((bits + 7) / 8)) + check(BitStream.validate_offset_bytes(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong,bytes - ((bits + 7) / 8).toInt)) + }.ensuring(_ => BitStream.validate_offset_bytes(b2.buf.length.toLong, b2.currentByte.toLong, b2.currentBit.toLong,bytes - ((bits + 7) / 8).toInt)) + } + + @ghost @pure @opaque @inlineOnce + def validateOffsetImpliesMoveBits(b: BitStream, bits: Long): Unit = { + require(0 <= bits && bits <= b.buf.length.toLong * 8L) + require(BitStream.validate_offset_bits(b.buf.length.toLong, b.currentByte.toLong, b.currentBit.toLong, bits)) + + { + () + }.ensuring(_ => moveBitIndexPrecond(b, bits)) } + // For showing invertibility of encoding - not fully integrated yet + /* @ghost @pure @opaque @inlineOnce def readBytePrefixLemma(bs1: BitStream, bs2: BitStream): Unit = { - require(bs1.buf.length <= bs2.buf.length) - require(bs1.bitIndex() + 8 <= bs1.buf.length.toLong * 8L) - require(bs1.bitIndex() + 8 <= bs2.bitIndex()) + require(bs1.buf.length == bs2.buf.length) + require(BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 8 <= bs1.buf.length.toLong * 8L) + require(BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 8 <= BitStream.bitIndex(bs2.buf.length, bs2.currentByte, bs2.currentBit )) require(arrayBitRangesEq( bs1.buf, bs2.buf, 0, - bs1.bitIndex() + 8 + BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 8 )) val bs2Reset = BitStream(snapshot(bs2.buf), bs1.currentByte, bs1.currentBit) @@ -106,13 +224,406 @@ object BitStream { val (bs2Res, b2) = bs2Reset.readBytePure() { - val end = (bs1.bitIndex() / 8 + 1).toInt + val end = (BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) / 8 + 1).toInt arrayRangesEqImpliesEq(bs1.buf, bs2.buf, 0, bs1.currentByte, end) }.ensuring { _ => - bs1Res.bitIndex() == bs2Res.bitIndex() && b1 == b2 + BitStream.bitIndex(bs1Res.buf.length, bs1Res.currentByte, bs1Res.currentBit ) == BitStream.bitIndex(bs2Res.buf.length, bs2Res.currentByte, bs2Res.currentBit ) && b1 == b2 } } + @ghost @pure @opaque @inlineOnce + def readByteRangesEq(bs1: BitStream, bs2: BitStream, rangeEqUntil: Long): Unit = { + require(bs1.buf.length == bs2.buf.length) + require(8 <= rangeEqUntil && BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) <= rangeEqUntil - 8 && rangeEqUntil <= bs1.buf.length.toLong * 8) + require(BitStream.validate_offset_byte(bs1.buf.length.toLong, bs1.currentByte.toLong, bs1.currentBit.toLong)) + require(arrayBitRangesEq( + bs1.buf, + bs2.buf, + 0, + rangeEqUntil + )) + + val bs2Reset = bs2.resetAt(bs1) + val read1 = bs1.readBytePure()._2 + val read2 = bs2Reset.readBytePure()._2 + + { + val aligned = BitStream.bitIndex(bs1.withAlignedByte().buf.length, bs1.withAlignedByte().currentByte, bs1.withAlignedByte().currentBit ) + arrayBitRangesEqSlicedLemma(bs1.buf, bs2.buf, 0, rangeEqUntil, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ), aligned) + arrayBitRangesEqSlicedLemma(bs1.buf, bs2.buf, 0, rangeEqUntil, aligned, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 8) + }.ensuring { _ => + read1 == read2 + } + } + + @ghost @pure @opaque @inlineOnce + def readBitPrefixLemma(bs1: BitStream, bs2: BitStream): Unit = { + require(bs1.buf.length == bs2.buf.length) + require(BitStream.validate_offset_bit(bs1.buf.length.toLong, bs1.currentByte.toLong, bs1.currentBit.toLong)) + require(arrayBitRangesEq( + bs1.buf, + bs2.buf, + 0, + BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1 + )) + + val bs2Reset = bs2.resetAt(bs1) + val (bs1Res, b1) = bs1.readBitPure() + val (bs2Res, b2) = bs2Reset.readBitPure() + + { + arrayBitRangesEqImpliesEq(bs1.buf, bs2.buf, 0, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ), BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1) + }.ensuring { _ => + BitStream.bitIndex(bs1Res.buf.length, bs1Res.currentByte, bs1Res.currentBit ) == BitStream.bitIndex(bs2Res.buf.length, bs2Res.currentByte, bs2Res.currentBit ) && b1 == b2 + } + } + + // TODO: "loopPrefixLemma" is a bad name, it's not the same "prefix lemma" as the others!!! + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsLoopPrefixLemma(bs: BitStream, nBits: Int, i: Int, acc: Long): Unit = { + require(0 <= i && i < nBits && nBits <= 64) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits - i)) + require((acc & onesLSBLong(nBits - i)) == 0L) + require((acc & onesLSBLong(nBits)) == acc) + decreases(nBits - i) + val (bsFinal, vGot1) = bs.readNLeastSignificantBitsLoopPure(nBits, i, acc) + val readBit = bs.readBitPure()._2 + val bs2 = bs.withMovedBitIndex(1) + val newAcc = acc | (if readBit then 1L << (nBits - 1 - i) else 0) + val (bs2Final, vGot2) = bs2.readNLeastSignificantBitsLoopPure(nBits, i + 1, newAcc) + + { + () + }.ensuring { _ => + vGot1 == vGot2 && bsFinal == bs2Final + } + } + + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsLoopPrefixLemma2(bs1: BitStream, bs2: BitStream, nBits: Int, i: Int, acc: Long): Unit = { + require(bs1.buf.length == bs2.buf.length) + require(0 <= i && i < nBits && nBits <= 64) + require(BitStream.validate_offset_bits(bs1.buf.length.toLong, bs1.currentByte.toLong, bs1.currentBit.toLong, nBits - i)) + require((acc & onesLSBLong(nBits - i)) == 0L) + require((acc & onesLSBLong(nBits)) == acc) + require(arrayBitRangesEq( + bs1.buf, + bs2.buf, + 0, + BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + nBits - i + )) + decreases(nBits - i) + + val bs2Reset = bs2.resetAt(bs1) + val (bsFinal1, vGot1) = bs1.readNLeastSignificantBitsLoopPure(nBits, i, acc) + val (bsFinal2, vGot2) = bs2Reset.readNLeastSignificantBitsLoopPure(nBits, i, acc) + + { + val (bs1Rec, gotB1) = bs1.readBitPure() + val (bs2Rec, gotB2) = bs2Reset.readBitPure() + arrayBitRangesEqSlicedLemma(bs1.buf, bs2.buf, 0, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + nBits - i, 0, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1) + readBitPrefixLemma(bs1, bs2) + assert(gotB1 == gotB2) + if (i == nBits - 1) { + check(vGot1 == vGot2) + check(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) + } else { + val accRec = acc | (if gotB1 then 1L << (nBits - 1 - i) else 0) + assert(BitStream.bitIndex(bs1Rec.buf.length, bs1Rec.currentByte, bs1Rec.currentBit ) == BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1) + validateOffsetBitsContentIrrelevancyLemma(bs1, bs1Rec.buf, 1) + readNLeastSignificantBitsLoopPrefixLemma2(bs1Rec, bs2Rec, nBits, i + 1, accRec) + val (_, vRecGot1) = bs1Rec.readNLeastSignificantBitsLoopPure(nBits, i + 1, accRec) + val (_, vRecGot2) = bs2Rec.readNLeastSignificantBitsLoopPure(nBits, i + 1, accRec) + assert(vRecGot1 == vRecGot2) + assert(vGot1 == vRecGot1) + assert(vGot2 == vRecGot2) + + check(vGot1 == vGot2) + check(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) + } + }.ensuring { _ => + vGot1 == vGot2 && BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit ) + } + } + + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsPrefixLemma(bs1: BitStream, bs2: BitStream, nBits: Int): Unit = { + require(bs1.buf.length == bs2.buf.length) + require(0 <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(bs1.buf.length.toLong, bs1.currentByte.toLong, bs1.currentBit.toLong, nBits)) + require(arrayBitRangesEq( + bs1.buf, + bs2.buf, + 0, + BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + nBits + )) + + val bs2Reset = bs2.resetAt(bs1) + val (bsFinal1, vGot1) = bs1.readNLeastSignificantBitsPure(nBits) + val (bsFinal2, vGot2) = bs2Reset.readNLeastSignificantBitsPure(nBits) + + { + if (nBits > 0) + readNLeastSignificantBitsLoopPrefixLemma2(bs1, bs2, nBits, 0, 0) + }.ensuring { _ => + vGot1 == vGot2 && BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit ) + } + } + + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsLoopNextLemma(bs: BitStream, nBits: Int, i: Int, acc1: Long): Unit = { + require(0 <= i && i < nBits && nBits <= 64) + require(1 <= nBits) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits - i)) + require((acc1 & onesLSBLong(nBits - i)) == 0L) + require((acc1 & onesLSBLong(nBits)) == acc1) + decreases(nBits - i) + + val (bsFinal1, vGot1) = bs.readNLeastSignificantBitsLoopPure(nBits, i, acc1) + val (bs2, bit) = bs.readBitPure() + val mask = if bit then 1L << (nBits - 1 - i) else 0 + val acc2 = (acc1 | mask) & onesLSBLong(nBits - 1) + val (bsFinal2, vGot2) = bs2.readNLeastSignificantBitsLoopPure(nBits - 1, i, acc2) + + { + if (i >= nBits - 2) () + else { + val acc1Rec = acc1 | mask + readNLeastSignificantBitsLoopNextLemma(bs2, nBits, i + 1, acc1Rec) + val (bsFinal1Rec, vGot1Rec) = bs2.readNLeastSignificantBitsLoopPure(nBits, i + 1, acc1Rec) + val (bs2Rec, bitRec) = bs2.readBitPure() + val maskRec = if bitRec then 1L << (nBits - 2 - i) else 0 + val acc2Rec = (acc1Rec | maskRec) & onesLSBLong(nBits - 1) + val (bsFinal2Rec, vGot2Rec) = bs2Rec.readNLeastSignificantBitsLoopPure(nBits - 1, i + 1, acc2Rec) + assert((vGot1Rec & onesLSBLong(nBits - 1)) == vGot2Rec) + assert(bsFinal1Rec == bsFinal2Rec) + + assert(bsFinal2 == bsFinal1Rec) + assert(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal1Rec.buf.length, bsFinal1Rec.currentByte, bsFinal1Rec.currentBit)) + assert(bsFinal1.buf == bsFinal1Rec.buf) + eqBufAndBitIndexImpliesEq(bsFinal1, bsFinal1Rec) + check(bsFinal1 == bsFinal2) + + assert(vGot1 == (vGot1Rec | mask)) + check((vGot1 & onesLSBLong(nBits - 1)) == vGot2) + } + }.ensuring { _ => + (vGot1 & onesLSBLong(nBits - 1)) == vGot2 && bsFinal1 == bsFinal2 + } + } + + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsLeadingZerosLemma(bs: BitStream, nBits: Int, leadingZeros: Int): Unit = { + require(0 <= leadingZeros && leadingZeros <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits)) + require(bs.readNLeastSignificantBitsPure(leadingZeros)._2 == 0L) + decreases(leadingZeros) + + val (bsFinal1, vGot1) = bs.readNLeastSignificantBitsPure(nBits) + val (bsFinal2, vGot2) = bs.withMovedBitIndex(leadingZeros).readNLeastSignificantBitsPure(nBits - leadingZeros) + + { + readNLeastSignificantBitsLeadingBitsLemma(bs, false, nBits, leadingZeros) + }.ensuring { _ => + vGot1 == vGot2 && bsFinal1 == bsFinal2 + } + } + + @ghost @pure @opaque @inlineOnce + def readNLeastSignificantBitsLeadingBitsLemma(bs: BitStream, bit: Boolean, nBits: Int, leadingBits: Int): Unit = { + require(0 <= leadingBits && leadingBits <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits)) + require(bs.readNLeastSignificantBitsPure(leadingBits)._2 == bitLSBLong(bit, leadingBits)) + decreases(leadingBits) + + val (bsFinal1, vGot1) = bs.readNLeastSignificantBitsPure(nBits) + val (bsFinal2, vGot2) = bs.withMovedBitIndex(leadingBits).readNLeastSignificantBitsPure(nBits - leadingBits) + + { + if (leadingBits == 0) () + else { + val (bsRec, gotBit) = bs.readBitPure() + assert(gotBit == bit) + readNLeastSignificantBitsLoopNextLemma(bs, leadingBits, 0, 0L) + readNLeastSignificantBitsLeadingBitsLemma(bsRec, bit, nBits - 1, leadingBits - 1) + eqBufAndBitIndexImpliesEq(bs.withMovedBitIndex(leadingBits), bsRec.withMovedBitIndex(leadingBits - 1)) + + val (bsFinal1Rec, vGot1Rec) = bsRec.readNLeastSignificantBitsPure(nBits - 1) + val (bsFinal2Rec, vGot2Rec) = bsRec.withMovedBitIndex(leadingBits - 1).readNLeastSignificantBitsPure(nBits - leadingBits) + assert(bsFinal1Rec == bsFinal2Rec) + assert(vGot1Rec == ((bitLSBLong(bit, leadingBits - 1) << (nBits - leadingBits)) | vGot2Rec)) + assert(bsFinal2 == bsFinal2Rec) + assert(vGot2 == vGot2Rec) + + readNLeastSignificantBitsLoopNextLemma(bs, nBits, 0, 0L) + assert(bsFinal1Rec == bsFinal1) + assert(vGot1 == (vGot1Rec | (if (bit) 1L << (nBits - 1) else 0L))) + check(vGot1 == ((bitLSBLong(bit, leadingBits) << (nBits - leadingBits)) | vGot2)) + check(bsFinal1 == bsFinal2) + } + }.ensuring { _ => + vGot1 == ((bitLSBLong(bit, leadingBits) << (nBits - leadingBits)) | vGot2) && bsFinal1 == bsFinal2 + } + } + + @ghost @pure @opaque @inlineOnce + def checkBitsLoopAndReadNLSB(bs: BitStream, nBits: Int, bit: Boolean, from: Int = 0): Unit = { + require(0 < nBits && nBits <= 64) + require(0 <= from && from <= nBits) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits - from)) + decreases(nBits - from) + val (bs1Final, ok) = bs.checkBitsLoopPure(nBits, bit, from) + require(ok) + val acc = if (bit) onesLSBLong(from) << (nBits - from) else 0 + val (bs2Final, vGot) = bs.readNLeastSignificantBitsLoopPure(nBits, from, acc) + + { + if (from == nBits) () + else { + val (bs1Rec, _) = bs.readBitPure() + checkBitsLoopAndReadNLSB(bs1Rec, nBits, bit, from + 1) + } + }.ensuring { _ => + if (!bit) vGot == 0 + else vGot == onesLSBLong(nBits) + } + } + + // TODO: Bad name + @ghost @pure @opaque @inlineOnce + def checkBitsLoopPrefixLemma(bs: BitStream, nBits: Long, expected: Boolean, from: Long): Unit = { + require(0 < nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= from && from < nBits) + require(BitStream.validate_offset_bits(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong, nBits - from)) + val (bsFinal, vGot1) = bs.checkBitsLoopPure(nBits, expected, from) + val readBit = bs.readBitPure()._2 + val bs2 = bs.withMovedBitIndex(1) + val (bs2Final, vGot2) = bs2.checkBitsLoopPure(nBits, expected, from + 1) + + { + () + }.ensuring { _ => + vGot1 == ((readBit == expected) && vGot2) && ((readBit == expected) ==> (bsFinal == bs2Final)) + } + } + + @ghost @pure @opaque @inlineOnce + def checkBitsLoopPrefixLemma2(bs1: BitStream, bs2: BitStream, nBits: Int, expected: Boolean, from: Long): Unit = { + require(bs1.buf.length == bs2.buf.length) + require(0 < nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= from && from < nBits) + require(BitStream.validate_offset_bits(bs1.buf.length.toLong, bs1.currentByte.toLong, bs1.currentBit.toLong, nBits - from)) + require(arrayBitRangesEq( + bs1.buf, + bs2.buf, + 0, + BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + nBits - from + )) + decreases(nBits - from) + + val bs2Reset = bs2.resetAt(bs1) + val (bsFinal1, vGot1) = bs1.checkBitsLoopPure(nBits, expected, from) + val (bsFinal2, vGot2) = bs2Reset.checkBitsLoopPure(nBits, expected, from) + + val bsFinal1PureBitIndex = BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) + val bsFinal2PureBitIndex = BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit ) + + { + val (bs1Rec, gotB1) = bs1.readBitPure() + val (bs2Rec, gotB2) = bs2Reset.readBitPure() + arrayBitRangesEqSlicedLemma(bs1.buf, bs2.buf, 0, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + nBits - from, 0, BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1) + readBitPrefixLemma(bs1, bs2) + assert(gotB1 == gotB2) + if (from == nBits - 1) { + check(vGot1 == vGot2) + assert(BitStream.invariant(bsFinal1)) + check(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) + } else { + assert(BitStream.invariant(bs1Rec)) + assert(BitStream.bitIndex(bs1Rec.buf.length, bs1Rec.currentByte, bs1Rec.currentBit ) == BitStream.bitIndex(bs1.buf.length, bs1.currentByte, bs1.currentBit ) + 1) + validateOffsetBitsContentIrrelevancyLemma(bs1, bs1Rec.buf, 1) + assert(BitStream.invariant(bs1Rec)) + assert((BitStream.validate_offset_bits(bs1Rec.buf.length.toLong, bs1Rec.currentByte.toLong, bs1Rec.currentBit.toLong, nBits - from - 1))) + checkBitsLoopPrefixLemma2(bs1Rec, bs2Rec, nBits, expected, from + 1) + + val (_, vRecGot1) = bs1Rec.checkBitsLoopPure(nBits, expected, from + 1) + assert((BitStream.validate_offset_bits(bs2Rec.buf.length.toLong, bs2Rec.currentByte.toLong, bs2Rec.currentBit.toLong, nBits - from - 1))) + val (_, vRecGot2) = bs2Rec.checkBitsLoopPure(nBits, expected, from + 1) + + assert(vRecGot1 == vRecGot2) + assert(vGot1 == ((gotB1 == expected) && vRecGot1)) + assert(vGot2 == ((gotB1 == expected) && vRecGot2)) + + check(vGot1 == vGot2) + assert(BitStream.invariant(bsFinal2.currentBit, bsFinal2.currentByte, bsFinal2.buf.length)) + assert(BitStream.invariant(bsFinal1.currentBit, bsFinal1.currentByte, bsFinal1.buf.length)) + assert(bsFinal2PureBitIndex == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) + assert(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == bsFinal1PureBitIndex) + assert(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) // 200sec!!! + check(BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit )) + } + }.ensuring { _ => + vGot1 == vGot2 && BitStream.bitIndex(bsFinal1.buf.length, bsFinal1.currentByte, bsFinal1.currentBit ) == BitStream.bitIndex(bsFinal2.buf.length, bsFinal2.currentByte, bsFinal2.currentBit ) + } + } + + @ghost @pure @opaque @inlineOnce + def readByteArrayLoopAnyArraysLemma(bs: BitStream, arr1: Array[UByte], arr2: Array[UByte], from: Int, to: Int): Unit = { + require(arr1.length <= arr2.length) + require(0 <= from && from <= to && to <= arr1.length) + require( BitStream.validate_offset_bytes(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong,to - from)) + decreases(to - from) + + val (_, arr1b) = bs.readByteArrayLoopPure(arr1, from, to) + val (_, arr2b) = bs.readByteArrayLoopPure(arr2, from, to) + + { + if (from == to) { + () + } else { + val bsRec = bs.withMovedByteIndex(1) + val b = bs.readBytePure()._2 + validateOffsetBytesFromBitIndexLemma(bs, bsRec, 8, to - from) + readByteArrayLoopAnyArraysLemma(bsRec, arr1.updated(from, b), arr2.updated(from, b), from + 1, to) + } + }.ensuring(_ => arrayRangesEq(arr1b, arr2b, from, to)) + } + + @ghost @pure @opaque @inlineOnce + def readByteArrayLoopArrayPrefixLemma(bs: BitStream, arr: Array[UByte], from: Int, to: Int): Unit = { + require(0 <= from && from < to && to <= arr.length) + require( BitStream.validate_offset_bytes(bs.buf.length.toLong, bs.currentByte.toLong, bs.currentBit.toLong,to - from)) + decreases(to - from) + val (_, arr1) = bs.readByteArrayLoopPure(arr, from, to) + val bs2 = bs.withMovedByteIndex(1) + val (_, arr2) = bs2.readByteArrayLoopPure(arr.updated(from, bs.readBytePure()._2), from + 1, to) + + { + if (from == to - 1) { + () + } else { + val bsRec = bs.withMovedByteIndex(1) + val b1 = bs.readBytePure()._2 + val b2 = bs2.readBytePure()._2 + val arr_rec = arr.updated(from, b1) + validateOffsetBytesFromBitIndexLemma(bs, bsRec, 8, to - from) + readByteArrayLoopArrayPrefixLemma(bsRec, arr_rec, from + 1, to) + } + }.ensuring { _ => + arrayRangesEq(arr1, arr2, 0, to) + } + } + + @ghost @pure @opaque @inlineOnce + def validReflexiveLemma(bs: BitStream): Unit = { + if (bs.buf.length != 0) { + arrayBitEqImpliesRangesEqLemma(bs.buf) + arrayBitRangesEqSlicedLemma(bs.buf, snapshot(bs.buf), 0, bs.buf.length.toLong * 8, 0, BitStream.bitIndex(bs.buf.length, bs.currentByte, bs.currentBit )) + } + }.ensuring { _ => + bs.isPrefixOf(snapshot(bs)) + } + @ghost @pure @opaque @inlineOnce def validTransitiveLemma(w1: BitStream, w2: BitStream, w3: BitStream): Unit = { require(w1.isPrefixOf(w2)) @@ -133,6 +644,7 @@ object BitStream { }.ensuring { _ => w1.isPrefixOf(w3) } + */ def moveByteIndexPrecond(b: BitStream, diffInBytes: Int): Boolean = { -b.buf.length <= diffInBytes && diffInBytes <= b.buf.length && { @@ -143,23 +655,12 @@ object BitStream { def moveBitIndexPrecond(b: BitStream, diffInBits: Long): Boolean = { // This condition ensures we do not have an overflow in `res`, should always hold and is easier to verify than the general condition for no overflow -8 * b.buf.length.toLong <= diffInBits && diffInBits <= 8 * b.buf.length.toLong && { - val res = b.bitIndex() + diffInBits + val res = BitStream.bitIndex(b.buf.length, b.currentByte, b.currentBit ) + diffInBits 0 <= res && res <= 8 * b.buf.length.toLong } } } -private val BitAccessMasks: Array[Byte] = Array( - -0x80, // -128 / 1000 0000 / x80 - 0x40, // 64 / 0100 0000 / x40 - 0x20, // 32 / 0010 0000 / x20 - 0x10, // 16 / 0001 0000 / x10 - 0x08, // 8 / 0000 1000 / x08 - 0x04, // 4 / 0000 0100 / x04 - 0x02, // 2 / 0000 0010 / x02 - 0x01, // 1 / 0000 0001 / x01 -) - case class BitStream private [asn1scala]( var buf: Array[Byte], var currentByte: Int = 0, // marks the currentByte that gets accessed @@ -168,46 +669,11 @@ case class BitStream private [asn1scala]( import BitStream.* require(BitStream.invariant(currentBit, currentByte, buf.length)) - - @pure - def remainingBits: Long = { - (buf.length.toLong * NO_OF_BITS_IN_BYTE) - (currentByte.toLong * NO_OF_BITS_IN_BYTE + currentBit) - } - - @pure - def validate_offset_bit(): Boolean = { - remainingBits >= 1 - }.ensuring(_ => BitStream.invariant(this)) - - @pure - def validate_offset_bits(bits: Long = 0): Boolean = { - require(bits >= 0) - remainingBits >= bits - }.ensuring(_ => BitStream.invariant(this)) - - @pure - def validate_offset_byte(): Boolean = { - remainingBits >= NO_OF_BITS_IN_BYTE - }.ensuring(_ => BitStream.invariant(this)) - - @pure - def validate_offset_bytes(bytes: Int): Boolean = { - require(bytes >= 0) - bytes <= remainingBits / NO_OF_BITS_IN_BYTE - }.ensuring(_ => BitStream.invariant(this)) - - @pure - def bitIndex(): Long = { - currentByte.toLong * NO_OF_BITS_IN_BYTE + currentBit - }.ensuring(res => - res == buf.length.toLong * NO_OF_BITS_IN_BYTE - remainingBits - ) - @pure def isPrefixOf(b2: BitStream): Boolean = { - buf.length <= b2.buf.length && - bitIndex() <= b2.bitIndex() && - (buf.length != 0) ==> arrayBitRangesEq(buf, b2.buf, 0, bitIndex()) + buf.length == b2.buf.length && + BitStream.bitIndex(buf.length, currentByte, currentBit) <= BitStream.bitIndex(b2.buf.length, b2.currentByte, b2.currentBit ) && + (buf.length != 0) ==> arrayBitRangesEq(buf, b2.buf, 0, BitStream.bitIndex(buf.length, currentByte, currentBit)) } def resetBitIndex(): Unit = { @@ -216,7 +682,7 @@ case class BitStream private [asn1scala]( } private def increaseBitIndex(): Unit = { - require(remainingBits > 0) + require(BitStream.remainingBits(buf.length.toLong, currentByte.toLong, currentBit.toLong) > 0) if currentBit < NO_OF_BITS_IN_BYTE - 1 then currentBit += 1 else @@ -225,8 +691,8 @@ case class BitStream private [asn1scala]( }.ensuring {_ => val oldBitStr = old(this) - oldBitStr.bitIndex() + 1 == this.bitIndex() &&& - oldBitStr.remainingBits - remainingBits == 1 &&& + BitStream.bitIndex(oldBitStr.buf.length, oldBitStr.currentByte, oldBitStr.currentBit) + 1 == BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit ) &&& + BitStream.remainingBits(oldBitStr.buf.length.toLong, oldBitStr.currentByte.toLong, oldBitStr.currentBit.toLong) - BitStream.remainingBits(buf.length.toLong, currentByte.toLong, currentBit.toLong) == 1 &&& oldBitStr.buf.length == buf.length } @@ -243,7 +709,7 @@ case class BitStream private [asn1scala]( currentByte += 1 else currentBit += nbBits - }.ensuring(_ => old(this).bitIndex() + diffInBits == bitIndex()) + }.ensuring(_ => BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + diffInBits == BitStream.bitIndex(buf.length, currentByte, currentBit)) @ghost @pure def withMovedBitIndex(diffInBits: Long): BitStream = { @@ -266,7 +732,7 @@ case class BitStream private [asn1scala]( cpy } - + @pure @inline def getBufferLength: Int = buf.length /** @@ -279,6 +745,7 @@ case class BitStream private [asn1scala]( * Currentbyte = 14, currentBit = 0 --> 14 * */ + @pure @inline def getLength: Int = { var ret: Int = currentByte if currentBit > 0 then @@ -289,17 +756,20 @@ case class BitStream private [asn1scala]( @ghost @pure @inline def getBuf: Array[Byte] = buf + @pure @inline + def bitIndex: Long = BitStream.bitIndex(buf.length, currentByte, currentBit) + + @pure @inline + def validate_offset_bits(bits: Long): Boolean = { + require(0 <= bits) + BitStream.validate_offset_bits(buf.length, currentByte, currentBit, bits) + } + @ghost @pure @inline - def resetAt(b: BitStream): BitStream = + def resetAt(b: BitStream): BitStream = { + require(b.buf.length == buf.length) BitStream(snapshot(buf), b.currentByte, b.currentBit) - -// @ghost -// @pure -// private def readBitPure(): (BitStream, Option[Boolean]) = { -// require(validate_offset_bit()) -// val cpy = snapshot(this) -// (cpy, cpy.readBit()) -// } + } ensuring(res => invariant(res)) // ****************** Append Bit Functions ********************** @@ -315,24 +785,40 @@ case class BitStream private [asn1scala]( * 0 1 2 3 4 5 6 7 * */ + @opaque @inlineOnce def appendBit(b: Boolean): Unit = { - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) + + @ghost val oldThis = snapshot(this) + if b then buf(currentByte) = (buf(currentByte) | BitAccessMasks(currentBit)).toByte else buf(currentByte) = (buf(currentByte) & (~BitAccessMasks(currentBit))).toByte + ghostExpr { + arrayUpdatedAtPrefixLemma(oldThis.buf, currentByte, buf(currentByte)) + } + increaseBitIndex() - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - 1) // NOTE: needs cvc5 for solving + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + 1 /* && w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + val (r2Got, bGot) = r1.readBitPure() + bGot == b && r2Got == r2 + }*/ + } /** * Append a set bit */ def appendBitOne(): Unit = { - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) appendBit(true) - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - 1) + }.ensuring(_ => buf.length == old(this).buf.length && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + 1) /** * Append n set bits to bitstream @@ -340,33 +826,22 @@ case class BitStream private [asn1scala]( * @param nBits number of bits * */ + @opaque @inlineOnce def appendNOneBits(nBits: Long): Unit = { - require(nBits >= 0) - require(validate_offset_bits(nBits)) - - @ghost val oldThis = snapshot(this) - var i = 0L - (while i < nBits do - decreases(nBits - i) - appendBitOne() - i += 1 - ).invariant( - 0 <= i && i <= nBits && - nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong && - buf.length == oldThis.buf.length && - remainingBits == oldThis.remainingBits - i && - validate_offset_bits(nBits - i)) - - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - nBits) + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + appendNBits(nBits, true) + } /** * Append cleared bit to bitstream */ + @opaque @inlineOnce def appendBitZero(): Unit = { - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) appendBit(false) - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - 1) + }.ensuring(_ => buf.length == old(this).buf.length && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + 1) /** * Append n cleared bits to bitstream @@ -374,24 +849,95 @@ case class BitStream private [asn1scala]( * @param nBits number of bits * */ + @opaque @inlineOnce def appendNZeroBits(nBits: Long): Unit = { - require(nBits >= 0) - require(validate_offset_bits(nBits)) + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + appendNBits(nBits, false) + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length + && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit ) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + nBits + /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1, w2.buf, nBits) + val (r2Got, bGot) = r1.checkBitsLoopPure(nBits, false, 0) + bGot && r2Got == r2 + }*/ + } - @ghost val oldThis = snapshot(this) - var i = 0L - (while i < nBits do - decreases(nBits - i) - appendBitZero() - i += 1 - ).invariant( - 0 <= i && i <= nBits && - nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong && - buf.length == oldThis.buf.length && - remainingBits == oldThis.remainingBits - i && - validate_offset_bits(nBits - i)) + @opaque @inlineOnce + def appendNBits(nBits: Long, bit: Boolean): Unit = { + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + appendNBitsLoop(nBits, bit, 0) + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length + && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit ) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + nBits + /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1, w2.buf, nBits) + val (r2Got, bGot) = r1.checkBitsLoopPure(nBits, bit, 0) + bGot && r2Got == r2 + }*/ + } - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - nBits) + @opaque @inlineOnce + def appendNBitsLoop(nBits: Long, bit: Boolean, from: Long): Unit = { + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= from && from <= nBits) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - from)) + decreases(nBits - from) + if (from < nBits) { + @ghost val oldThis1 = snapshot(this) + appendBit(bit) + // @ghost val oldThis2 = snapshot(this) + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(oldThis1, this, nBits - from, 1) + } + appendNBitsLoop(nBits, bit, from + 1) + /* + ghostExpr { + validTransitiveLemma(oldThis1, oldThis2, this) + readBitPrefixLemma(oldThis2.resetAt(oldThis1), this) + + val (r1_13, r3_13) = reader(oldThis1, this) + val (r2_23, r3_23) = reader(oldThis2, this) + val (_, bitGot) = r1_13.readBitPure() + check(bitGot == bit) + + validateOffsetBitsContentIrrelevancyLemma(oldThis1, this.buf, nBits - from) + val (r3Got_13, resGot_13) = r1_13.checkBitsLoopPure(nBits, bit, from) + + validateOffsetBitsContentIrrelevancyLemma(oldThis2, this.buf, nBits - from - 1) + val (r3Got_23, resGot_23) = r2_23.checkBitsLoopPure(nBits, bit, from + 1) + + assert(r3Got_23 == r3_23) + + checkBitsLoopPrefixLemma(r1_13, nBits, bit, from) + assert(r2_23 == r1_13.withMovedBitIndex(1)) + check(resGot_13 == resGot_23) + check(r3Got_13 == r3_13) + } + */ + } /*else { + ghostExpr { + validReflexiveLemma(this) + } + }*/ + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + (nBits - from) /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1, w2.buf, nBits - from) + val (r2Got, bGot) = r1.checkBitsLoopPure(nBits, bit, from) + bGot && r2Got == r2 + }*/ + } /** * Append bit with bitNr from b to bitstream @@ -404,14 +950,15 @@ case class BitStream private [asn1scala]( * bit 8 as LSB - but we start from 0 in CS * */ + @opaque @inlineOnce private def appendBitFromByte(b: Byte, bitNr: Int): Unit = { require(bitNr >= 0 && bitNr < NO_OF_BITS_IN_BYTE) - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) val bitPosInByte = 1 << ((NO_OF_BITS_IN_BYTE - 1) - bitNr) appendBit((b.unsignedToInt & bitPosInByte) != 0) - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - 1) + }.ensuring(_ => buf.length == old(this).buf.length && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + 1) /** * Append nBits from the 64bit Integer value v to the bitstream @@ -422,11 +969,14 @@ case class BitStream private [asn1scala]( * Remarks: * bit 0 is the LSB of v */ + @opaque @inlineOnce def appendBitsLSBFirst(v: Long, nBits: Int): Unit = { require(nBits >= 0 && nBits <= NO_OF_BITS_IN_LONG) - require(validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) -// @ghost val oldThis = snapshot(this) + @ghost val oldThis = snapshot(this) + assert(BitStream.invariant(this)) + assert(BitStream.invariant(currentBit, currentByte, buf.length)) var i = 0 (while i < nBits do decreases(nBits - i) @@ -437,8 +987,12 @@ case class BitStream private [asn1scala]( appendBit(b) i += 1 - ).invariant(i >= 0 && i <= nBits &&& validate_offset_bits(nBits - i)) - } + assert(BitStream.invariant(currentBit, currentByte, buf.length)) + ).invariant(i >= 0 && BitStream.invariant(currentBit, currentByte, buf.length) && i <= nBits &&& + buf.length == oldThis.buf.length &&& + BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(oldThis.buf.length, oldThis.currentByte, oldThis.currentBit) + i &&& + BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - i)) + }.ensuring(_ => buf.length == old(this).buf.length && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + nBits) /** * Append nBits from the 64bit Integer value v to the bitstream @@ -460,21 +1014,76 @@ case class BitStream private [asn1scala]( * After bit 24, bit 23 and so on get added * */ + @opaque @inlineOnce def appendNLeastSignificantBits(v: Long, nBits: Int): Unit = { require(nBits >= 0 && nBits <= NO_OF_BITS_IN_LONG) - require(validate_offset_bits(nBits)) - - var i = nBits - 1 - (while i >= 0 do - decreases(i) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + require((v & onesLSBLong(nBits)) == v) + appendNLeastSignificantBitsLoop(v, nBits, 0) + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit ) + nBits /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1, w2.buf, nBits) + val (r2Got, vGot) = r1.readNLeastSignificantBitsPure(nBits) + vGot == v && r2Got == r2 + }*/ + } - val ii = v & (1L << i) + @opaque @inlineOnce + def appendNLeastSignificantBitsLoop(v: Long, nBits: Int, i: Int): Unit = { + require(0 <= i && i <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - i)) + require((v & onesLSBLong(nBits)) == v) + decreases(nBits - i) + if (i < nBits) { + val ii = v & (1L << (nBits - 1 - i)) val b = ii != 0 - + // @ghost val oldThis1 = snapshot(this) appendBit(b) - - i -= 1 - ).invariant(i >= -1 && i <= nBits &&& validate_offset_bits(i+1)) + // @ghost val oldThis2 = snapshot(this) + appendNLeastSignificantBitsLoop(v, nBits, i + 1) + /* + ghostExpr { + validTransitiveLemma(oldThis1, oldThis2, this) + readBitPrefixLemma(oldThis2.resetAt(oldThis1), this) + + val (r1_13, r3_13) = reader(oldThis1, this) + val (r2_23, r3_23) = reader(oldThis2, this) + val (_, bitGot) = r1_13.readBitPure() + check(bitGot == b) + + val zeroed = v & ~onesLSBLong(nBits - i) + validateOffsetBitsContentIrrelevancyLemma(oldThis1, this.buf, nBits - i) + val (r3Got_13, resGot_13) = r1_13.readNLeastSignificantBitsLoopPure(nBits, i, zeroed) + + val upd = zeroed | (if bitGot then 1L << (nBits - 1 - i) else 0) + validateOffsetBitsContentIrrelevancyLemma(oldThis2, this.buf, nBits - i - 1) + val (r3Got_23, resGot_23) = r2_23.readNLeastSignificantBitsLoopPure(nBits, i + 1, upd) + + assert(r3Got_23 == r3_23) + + readNLeastSignificantBitsLoopPrefixLemma(r1_13, nBits, i, zeroed) + assert(r2_23 == r1_13.withMovedBitIndex(1)) + check(resGot_13 == resGot_23) + check(r3Got_13 == r3_13) + }*/ + } /*else { + ghostExpr { + validReflexiveLemma(this) + } + }*/ + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit ) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit ) + (nBits - i) /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + val zeroed = v & ~onesLSBLong(nBits - i) + validateOffsetBitsContentIrrelevancyLemma(w1, w2.buf, nBits - i) + val (r2Got, vGot) = r1.readNLeastSignificantBitsLoopPure(nBits, i, zeroed) + vGot == v && r2Got == r2 + }*/ } /** @@ -482,29 +1091,39 @@ case class BitStream private [asn1scala]( * * @param srcBuffer source of the bits to add * @param nBits number of bits to add + * @param from start index in srcBuffer (in bits index, not UByte!!) * * Remarks: * bit 0 is the MSB of the first byte of srcBuffer * */ - def appendBitsMSBFirst(srcBuffer: Array[UByte], nBits: Long): Unit = { - require(nBits >= 0 && (nBits / 8) < srcBuffer.length) - require(validate_offset_bits(nBits)) + @opaque @inlineOnce + def appendBitsMSBFirst(srcBuffer: Array[UByte], nBits: Long, from: Long = 0): Unit = { + require(nBits >= 0) + require(from >= 0) + require(from < Long.MaxValue - nBits) + require(nBits + from <= srcBuffer.length.toLong * 8L) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) @ghost val oldThis = snapshot(this) - var i = 0L - (while i < nBits do - decreases(nBits - i) - + @ghost val oldSrcBuffer = snapshot(srcBuffer) + var i = from // from + val to = from + nBits + (while i < to do + decreases(to - i) + @ghost val beforeAppend = snapshot(this) appendBitFromByte(srcBuffer((i / NO_OF_BITS_IN_BYTE).toInt).toRaw, (i % NO_OF_BITS_IN_BYTE).toInt) - + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(beforeAppend, this, to - i, 1) + } i += 1L - ).invariant(i >= 0 &&& i <= nBits &&& i / NO_OF_BITS_IN_BYTE <= Int.MaxValue &&& + ).invariant(i >= from &&& i <= to &&& i / NO_OF_BITS_IN_BYTE <= Int.MaxValue &&& + srcBuffer == oldSrcBuffer &&& buf.length == oldThis.buf.length &&& - remainingBits == oldThis.remainingBits - i &&& - validate_offset_bits(nBits - i)) + BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(oldThis.buf.length, oldThis.currentByte, oldThis.currentBit ) + (i - from) &&& + BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, to - i)) - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - nBits) + }.ensuring(_ => srcBuffer == old(srcBuffer) && buf.length == old(this).buf.length && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + nBits) // ****************** Append Byte Functions ********************** @@ -530,7 +1149,7 @@ case class BitStream private [asn1scala]( @opaque @inlineOnce def appendPartialByte(v: UByte, nBits: Int): Unit = { require(nBits >= 1 && nBits < NO_OF_BITS_IN_BYTE) - require(validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) @ghost val oldThis = snapshot(this) @@ -544,7 +1163,7 @@ case class BitStream private [asn1scala]( val mask2 = MASK_B(8 - totalBits) val mask = (mask1 | mask2).toByte buf(currentByte) = wrappingExpr { ((buf(currentByte) & mask) | (vv << (8 - totalBits))).toByte } - ghostExpr { + /*ghostExpr { arrayUpdatedAtPrefixLemma(oldThis.buf, currentByte, buf(currentByte)) assert(arrayRangesEq(oldThis.buf, buf, 0, currentByte)) assert( @@ -555,16 +1174,16 @@ case class BitStream private [asn1scala]( oldThis.currentBit ) ) - } + }*/ moveBitIndex(nBits) else val totalBitsForNextByte = totalBits - 8 buf(currentByte) = wrappingExpr { ((buf(currentByte) & mask1) | ((vv & 0XFF) >>> totalBitsForNextByte)).toByte } - @ghost val oldThis2 = snapshot(this) + // @ghost val oldThis2 = snapshot(this) currentByte += 1 val mask = MASK_B(8 - totalBitsForNextByte).toByte buf(currentByte) = wrappingExpr { ((buf(currentByte) & mask) | (vv << (8 - totalBitsForNextByte))).toByte } - ghostExpr { + /*ghostExpr { arrayUpdatedAtPrefixLemma(oldThis.buf, currentByte - 1, buf(currentByte - 1)) arrayUpdatedAtPrefixLemma(oldThis2.buf, currentByte, buf(currentByte)) arrayRangesEqTransitive( @@ -581,16 +1200,16 @@ case class BitStream private [asn1scala]( totalBitsForNextByte ) ) - } + }*/ currentBit = totalBitsForNextByte }.ensuring { _ => val w1 = old(this) val w2 = this - w2.bitIndex() == w1.bitIndex() + nBits && w1.isPrefixOf(w2) && { + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + nBits /* && w1.isPrefixOf(w2) && { val (r1, r2) = reader(w1, w2) val (r2Got, vGot) = r1.readPartialBytePure(nBits) vGot.toRaw == wrappingExpr { (v.toRaw & MASK_B(nBits)).toByte } && r2Got == r2 - } + }*/ } /** @@ -615,9 +1234,9 @@ case class BitStream private [asn1scala]( * */ @opaque @inlineOnce def appendByte(v: UByte): Unit = { - require(validate_offset_bytes(1)) + require(BitStream.validate_offset_byte(buf.length.toLong, currentByte.toLong, currentBit.toLong)) - @ghost val oldThis = snapshot(this) + // @ghost val oldThis = snapshot(this) val cb = currentBit.toByte val ncb = (8 - cb).toByte var mask = (~MASK_B(ncb)).toByte @@ -626,7 +1245,7 @@ case class BitStream private [asn1scala]( buf(currentByte) = wrappingExpr { (buf(currentByte) | ((v.toRaw & 0xFF) >>> cb)).toByte } currentByte += 1 - ghostExpr { + /*ghostExpr { check( (oldThis.currentByte < oldThis.buf.length) ==> byteRangesEq( @@ -634,14 +1253,14 @@ case class BitStream private [asn1scala]( buf(oldThis.currentByte), 0, oldThis.currentBit)) } - @ghost val oldThis2 = snapshot(this) + @ghost val oldThis2 = snapshot(this)*/ if cb > 0 then mask = (~mask).toByte buf(currentByte) = wrappingExpr { (buf(currentByte) & mask).toByte } buf(currentByte) = wrappingExpr { (buf(currentByte) | (v.toRaw << ncb)).toByte } - ghostExpr { + /*ghostExpr { arrayUpdatedAtPrefixLemma(oldThis.buf, currentByte - 1, buf(currentByte - 1)) assert(arrayRangesEq(oldThis.buf, oldThis2.buf, 0, currentByte - 1)) @@ -667,15 +1286,15 @@ case class BitStream private [asn1scala]( 0, oldThis.currentByte )) - } + }*/ }.ensuring { _ => val w1 = old(this) val w2 = this - w1.buf.length == w2.buf.length && w2.bitIndex() == w1.bitIndex() + 8 && w1.isPrefixOf(w2) && { + w1.buf.length == w2.buf.length && BitStream.bitIndex(w2.buf.length, w2.currentByte, w2.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + 8 /*&& w1.isPrefixOf(w2) && { val (r1, r2) = reader(w1, w2) val (r2Got, vGot) = r1.readBytePure() vGot == v && r2Got == r2 - } + }*/ } /** @@ -690,23 +1309,65 @@ case class BitStream private [asn1scala]( */ def appendByteArray(arr: Array[UByte], noOfBytes: Int): Unit = { require(0 <= noOfBytes && noOfBytes <= arr.length) - require(validate_offset_bytes(noOfBytes)) - - @ghost val oldThis = snapshot(this) - var i: Int = 0 - (while i < noOfBytes do - decreases(noOfBytes - i) + require(BitStream.validate_offset_bytes(buf.length.toLong, currentByte.toLong, currentBit.toLong, noOfBytes)) - appendByte(arr(i)) - - i += 1 - ).invariant( - 0 <= i && i <= noOfBytes && - buf.length == oldThis.buf.length && - remainingBits == oldThis.remainingBits - i.toLong * NO_OF_BITS_IN_BYTE && - validate_offset_bytes(noOfBytes - i)) + appendByteArrayLoop(arr, 0, noOfBytes) + } - }.ensuring(_ => buf.length == old(this).buf.length && remainingBits == old(this).remainingBits - noOfBytes.toLong * NO_OF_BITS_IN_BYTE) + @opaque @inlineOnce + def appendByteArrayLoop(arr: Array[UByte], from: Int, to: Int): Unit = { + require(0 <= from && from <= to && to <= arr.length) + require(BitStream.validate_offset_bytes(buf.length.toLong, currentByte.toLong, currentBit.toLong, to - from)) + decreases(to - from) + if (from < to) { + @ghost val oldThis1 = snapshot(this) + assert(oldThis1.buf.length.toLong == buf.length.toLong) + assert(oldThis1.currentByte.toLong == currentByte.toLong) + assert(oldThis1.currentBit.toLong == currentBit.toLong) + assert(BitStream.invariant( oldThis1.currentBit, oldThis1.currentByte, oldThis1.buf.length)) + assert((BitStream.validate_offset_bytes(oldThis1.buf.length.toLong, oldThis1.currentByte.toLong, oldThis1.currentBit.toLong, to - from))) + appendByte(arr(from)) + // @ghost val oldThis2 = snapshot(this) + ghostExpr { + assert((BitStream.validate_offset_bytes(oldThis1.buf.length.toLong, oldThis1.currentByte.toLong, oldThis1.currentBit.toLong, to - from))) + validateOffsetBytesFromBitIndexLemma(oldThis1, this, 8, to - from) + } + appendByteArrayLoop(arr, from + 1, to) + /* + ghostExpr { + validTransitiveLemma(oldThis1, oldThis2, this) + val oldThis2Reset = oldThis2.resetAt(oldThis1) + readBytePrefixLemma(oldThis2Reset, this) + val (r1_13, r3_13) = reader(oldThis1, this) + val (r2_23, r3_23) = reader(oldThis2, this) + val (_, byteGot) = r1_13.readBytePure() + check(byteGot == arr(from)) + validateOffsetBytesContentIrrelevancyLemma(oldThis1, this.buf, to - from) + val (r3Got_13, arrGot_13) = r1_13.readByteArrayLoopPure(arr, from, to) + check(r3Got_13 == r3_13) + validateOffsetBytesContentIrrelevancyLemma(oldThis2, this.buf, to - from - 1) + val (r3Got_23, arrGot_23) = r2_23.readByteArrayLoopPure(arr.updated(from, byteGot), from + 1, to) + readByteArrayLoopArrayPrefixLemma(r1_13, arr, from, to) + assert(arrayRangesEq(arrGot_13, arrGot_23, 0, to)) + arrayRangesEqSymmetricLemma(arrGot_13, arrGot_23, 0, to) + arrayRangesEqTransitive(arr, arrGot_23, arrGot_13, 0, to, to) + check(arrayRangesEq(arr, arrGot_13, 0, to)) + }*/ + } /*else { + ghostExpr { + validReflexiveLemma(this) + } + }*/ + }.ensuring { _ => + val w1 = old(this) + val w3 = this + w1.buf.length == w3.buf.length && BitStream.bitIndex(w3.buf.length, w3.currentByte, w3.currentBit) == BitStream.bitIndex(w1.buf.length, w1.currentByte, w1.currentBit) + (to - from).toLong * 8L /*&& w1.isPrefixOf(w3) && { + val (r1, r3) = reader(w1, w3) + validateOffsetBitsContentIrrelevancyLemma(w1, w3.buf, to - from) + val (r3Got, arrGot) = r1.readByteArrayLoopPure(arr, from, to) + arrGot.length == arr.length && r3Got == r3 && arrayRangesEq(arr, arrGot, 0, to) + }*/ + } // ****************** Peak Functions ********************** @@ -718,7 +1379,7 @@ case class BitStream private [asn1scala]( */ @pure def peekBit(): Boolean = { - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) ((buf(currentByte) & 0xFF) & (BitAccessMasks(currentBit) & 0xFF)) > 0 } @@ -730,15 +1391,21 @@ case class BitStream private [asn1scala]( * @return next bit on the bitstream * */ + @opaque @inlineOnce def readBit(): Boolean = { - require(BitStream.invariant(this)) - require(validate_offset_bit()) + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) val ret = (buf(currentByte) & BitAccessMasks(currentBit)) != 0 - increaseBitIndex() - ret - }.ensuring(_ => buf == old(this).buf && remainingBits == old(this).remainingBits - 1) + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + 1) + + @ghost @pure + def readBitPure(): (BitStream, Boolean) = { + require(BitStream.validate_offset_bit(buf.length.toLong, currentByte.toLong, currentBit.toLong)) + val cpy = snapshot(this) + val b = cpy.readBit() + (cpy, b) + } /** * Read multiple bits from the bitstream @@ -768,28 +1435,108 @@ case class BitStream private [asn1scala]( * MSB byte 0 MSB byte 1 * */ + @opaque @inlineOnce def readBits(nBits: Long): Array[UByte] = { - require(nBits >= 0 && validate_offset_bits(nBits)) - assert(nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + val arrLen = ((nBits + NO_OF_BITS_IN_BYTE - 1) / NO_OF_BITS_IN_BYTE).toInt - val arr: Array[UByte] = Array.fill(arrLen)(0.toRawUByte) + val arr: Array[Byte] = Array.fill(arrLen)(0 : Byte) + readBitsLoop(nBits, arr, 0, nBits) + UByte.fromArrayRaws(arr) + } ensuring(res => + buf == old(this).buf && BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + nBits == BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit) && + BitStream.invariant(this.currentBit, this.currentByte, this.buf.length) && + res.length == ((nBits + NO_OF_BITS_IN_BYTE - 1) / NO_OF_BITS_IN_BYTE).toInt - @ghost val oldThis = snapshot(this) - var i = 0L - (while i < nBits do - decreases(nBits - i) + )// && old(this).currentByte <= this.currentByte) - arr((i / NO_OF_BITS_IN_BYTE).toInt) |||= (if readBit() then BitAccessMasks((i % NO_OF_BITS_IN_BYTE).toInt) else 0) + @opaque @inlineOnce + def readBitsLoop(nBits: Long, arr: Array[Byte], from: Long, to: Long): Unit = { + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(arr.length >= ((nBits + NO_OF_BITS_IN_BYTE - 1) / NO_OF_BITS_IN_BYTE)) + require(0 <= from && from <= to && to <= nBits) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - from)) + decreases(to - from) + if (from < to) { + @ghost val arr1 = snapshot(arr) + @ghost val oldThis1 = snapshot(this) + + val bit = readBit() + val byteIx = (from / NO_OF_BITS_IN_BYTE).toInt + val bitIx = (from % NO_OF_BITS_IN_BYTE).toInt + + arr(byteIx) = stainless.math.wrapping { ((arr(byteIx) & ~BitAccessMasks(bitIx)) | (if bit then BitAccessMasks(bitIx) else 0)).toByte } + // @ghost val arr2 = snapshot(arr) + // @ghost val oldThis2 = snapshot(this) + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(oldThis1, this, nBits - from, 1) + } + readBitsLoop(nBits, arr, from + 1, to) - i += 1 - ).invariant(i >= 0 &&& i <= nBits &&& validate_offset_bits(nBits - i) &&& - (i / NO_OF_BITS_IN_BYTE) <= Int.MaxValue &&& - buf == oldThis.buf &&& - remainingBits == oldThis.remainingBits - i &&& - arr.length == arrLen) + ghostExpr { + check { + BitStream.bitIndex(oldThis1.buf.length, oldThis1.currentByte, oldThis1.currentBit ) + to - from == BitStream.bitIndex(buf.length, currentByte, currentBit) && + oldThis1.buf == buf && arr1.length == arr.length + } + /* + arrayBitRangesUpdatedAtLemma(arr1, from, bit) + arrayBitRangesEqTransitive(arr1, arr2, arr, 0, from, from + 1) + check(arrayBitRangesEq(arr1, arr, 0, from)) + + arrayBitRangesEqImpliesEq(arr2, arr, 0, from, from + 1) + check(arrayBitRangesEq(arr1, arr, 0, from)) + check(bitAt(arr, from) == bit)*/ + } + } else { + ghostExpr { + arrayBitRangesEqReflexiveLemma(arr) + arrayBitRangesEqSlicedLemma(arr, snapshot(arr), 0, arr.length.toLong * 8L, 0, from) + } + } + }.ensuring { _ => + BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + to - from == BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit ) && + old(this).buf == this.buf && + old(arr).length == arr.length && + // arrayBitRangesEq(old(arr), arr, 0, from) && + // ((from < to) ==> (bitAt(arr, from) == old(this).readBitPure()._2)) && + BitStream.invariant(this.currentBit, this.currentByte, this.buf.length) + } - arr - }.ensuring(_ => buf == old(this).buf && remainingBits == old(this).remainingBits - nBits) + @opaque @inlineOnce + def checkBitsLoop(nBits: Long, expected: Boolean, from: Long): Boolean = { + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= from && from <= nBits) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - from)) + decreases(nBits - from) + if (from == nBits) true + else { + @ghost val oldThis = snapshot(this) + val bit = readBit() + if (bit != expected) false + else { + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(oldThis, this, nBits - from, 1) + } + checkBitsLoop(nBits, expected, from + 1) + } + } + }.ensuring { ok => + BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + nBits - from >= BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit ) && + old(this).buf == this.buf && + (ok ==> (BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + nBits - from == BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit ))) /*&& + ((ok && from < nBits) ==> (expected == old(this).readBitPure()._2))*/ + } + + @ghost @pure + def checkBitsLoopPure(nBits: Long, expected: Boolean, from: Long): (BitStream, Boolean) = { + require(0 <= nBits && nBits <= Int.MaxValue.toLong * NO_OF_BITS_IN_BYTE.toLong) + require(0 <= from && from <= nBits) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - from)) + val cpy = snapshot(this) + val res = cpy.checkBitsLoop(nBits, expected, from) + (cpy, res) + } /** * Counter Operation to appendNLeastSignificantBits @@ -799,28 +1546,54 @@ case class BitStream private [asn1scala]( * Remarks: * The last bit from the bitstream will get written into the LSB */ + @opaque @inlineOnce def readNLeastSignificantBits(nBits: Int): Long = { require(nBits >= 0 && nBits <= 64) - require(validate_offset_bits(nBits)) - - var l: Long = 0 + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + readNLeastSignificantBitsLoop(nBits, 0, 0L) + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + nBits) - @ghost val oldThis = snapshot(this) - var i = 0 - (while i < nBits do - decreases(nBits - i) - - l |= (if readBit() then 1L << (nBits - 1 - i) else 0) + @ghost @pure + def readNLeastSignificantBitsPure(nBits: Int): (BitStream, Long) = { + require(nBits >= 0 && nBits <= 64) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) + val cpy = snapshot(this) + val res = cpy.readNLeastSignificantBits(nBits) + (cpy, res) + } - i += 1 - ).invariant( - i >= 0 && i <= nBits &&& - validate_offset_bits(nBits - i) &&& - buf == oldThis.buf &&& - remainingBits == oldThis.remainingBits - i) + @opaque @inlineOnce + def readNLeastSignificantBitsLoop(nBits: Int, i: Int, acc: Long): Long = { + require(0 <= i && i <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - i)) + require((acc & onesLSBLong(nBits - i)) == 0L) // The nBits - i LSBs must be 0 + require((acc & onesLSBLong(nBits)) == acc) + decreases(nBits - i) + if (nBits == i) { + acc + } else { + val bit = readBit() + val newAcc = acc | (if bit then 1L << (nBits - 1 - i) else 0) + readNLeastSignificantBitsLoop(nBits, i + 1, newAcc) + } + }.ensuring { res => + buf == old(this).buf && + BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + (nBits - i) && + (res >>> (nBits - i) == acc >>> (nBits - i)) && + (res & onesLSBLong(nBits)) == res /*&& + (i < nBits) ==> ((((res >>> (nBits - 1 - i)) & 1) == 1) == old(this).readBitPure()._2)*/ + } - l - }.ensuring(_ => buf == old(this).buf && remainingBits == old(this).remainingBits - nBits.toLong) + @ghost @pure + def readNLeastSignificantBitsLoopPure(nBits: Int, i: Int, acc: Long): (BitStream, Long) = { + require(0 <= i && i <= nBits && nBits <= 64) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits - i)) + require((acc & onesLSBLong(nBits - i)) == 0L) // The nBits - i LSBs must be 0 + require((acc & onesLSBLong(nBits)) == acc) + val cpy = snapshot(this) + val res = cpy.readNLeastSignificantBitsLoop(nBits, i, acc) + (cpy, res) + } // ****************** Read Byte Functions ********************** @@ -833,8 +1606,9 @@ case class BitStream private [asn1scala]( * First bit read from bitstream is the return bytes MSB * */ + @opaque @inlineOnce def readByte(): UByte = { - require(validate_offset_bits(8)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, 8)) val cb = currentBit.toByte val ncb = (8 - cb).toByte @@ -844,29 +1618,80 @@ case class BitStream private [asn1scala]( if cb > 0 then v = wrappingExpr { (v | (buf(currentByte) & 0xFF) >>> ncb).toByte } UByte.fromRaw(v) - }.ensuring(_ => buf == old(this).buf && bitIndex() == old(this).bitIndex() + 8) + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + 8) @ghost @pure def readBytePure(): (BitStream, UByte) = { - require(validate_offset_bits(8)) + require(BitStream.validate_offset_byte(buf.length.toLong, currentByte.toLong, currentBit.toLong)) val cpy = snapshot(this) val res = cpy.readByte() (cpy, res) } def readByteArray(nBytes: Int): Array[UByte] = { - require(nBytes <= Integer.MAX_VALUE / NO_OF_BITS_IN_BYTE) - require(nBytes >= 0 && nBytes <= remainingBits / NO_OF_BITS_IN_BYTE) - require(validate_offset_bytes(nBytes)) + require(nBytes >= 0) + require(BitStream.validate_offset_bytes(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBytes)) - // @ghost val oldThis = snapshot(this) - // val nBits = (nBytes * NO_OF_BITS_IN_BYTE).toLong - val res = readBits(nBytes * NO_OF_BITS_IN_BYTE) - // assert(remainingBits == oldThis.remainingBits - nBits) - // assert(nBits == nBytes.toLong * NO_OF_BITS_IN_BYTE) - res - }.ensuring(_ => buf == old(this).buf && remainingBits == old(this).remainingBits - nBytes.toLong * NO_OF_BITS_IN_BYTE) + val arr = Array.fill(nBytes)(UByte.fromRaw(0)) + readByteArrayLoop(arr, 0, nBytes) + arr + } + @opaque @inlineOnce + def readByteArrayLoop(arr: Array[UByte], i: Int, to: Int): Unit = { + require(0 <= i && i <= to && to <= arr.length) + require(BitStream.validate_offset_bytes(buf.length.toLong, currentByte.toLong, currentBit.toLong, to - i)) + decreases(to - i) + if (i < to) { + // @ghost val arr1 = snapshot(arr) + @ghost val oldThis1 = snapshot(this) + + val b = readByte() + arr(i) = b + + // @ghost val arr2 = snapshot(arr) + ghostExpr { + validateOffsetBytesFromBitIndexLemma(oldThis1, this, 8, to - i) + } + readByteArrayLoop(arr, i + 1, to) + + /*ghostExpr { + check { + BitStream.bitIndex(oldThis1.buf.length, oldThis1.currentByte, oldThis1.currentBit ) + (to - i).toLong * 8L == BitStream.bitIndex(buf.length, currentByte, currentBit) && + oldThis1.buf == buf && arr1.length == arr.length + } + + arrayUpdatedAtPrefixLemma(arr1, i, b) + arrayRangesEqTransitive(arr1, arr2, arr, 0, i, i + 1) + check(arrayRangesEq(arr1, arr, 0, i)) + + arrayRangesEqImpliesEq(arr2, arr, 0, i, i + 1) + check(arr(i) == b) + }*/ + } /*else { + ghostExpr { + arrayRangesEqReflexiveLemma(arr) + arrayRangesEqSlicedLemma(arr, snapshot(arr), 0, arr.length, 0, i) + } + }*/ + }.ensuring { _ => + BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit ) + (to - i).toLong * 8L == BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit ) && + old(this).buf == this.buf && + old(arr).length == arr.length /*&& + arrayRangesEq(old(arr), arr, 0, i) && + (i < to) ==> (arr(i) == old(this).readBytePure()._2)*/ + } + + @ghost @pure + def readByteArrayLoopPure(arr: Array[UByte], i: Int, to: Int): (BitStream, Array[UByte]) = { + require(0 <= i && i <= to && to <= arr.length) + require(BitStream.validate_offset_bytes(buf.length.toLong, currentByte.toLong, currentBit.toLong, to - i)) + + val cpy = snapshot(this) + val arrCpy = snapshot(arr) + cpy.readByteArrayLoop(arrCpy, i, to) + (cpy, arrCpy) + } /** * Read nBits from Bitstream into Byte @@ -898,9 +1723,10 @@ case class BitStream private [asn1scala]( * and written into v * */ + @opaque @inlineOnce def readPartialByte(nBits: Int): UByte = { require(nBits >= 1 && nBits < NO_OF_BITS_IN_BYTE) - require(validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) var v: Byte = 0 val cb = currentBit @@ -917,20 +1743,21 @@ case class BitStream private [asn1scala]( v = wrappingExpr { (v & MASK_B(nBits)).toByte } currentBit = totalBitsForNextByte UByte.fromRaw(v) - }.ensuring(_ => buf == old(this).buf && remainingBits == old(this).remainingBits - nBits) + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(buf.length, currentByte, currentBit) == BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + nBits) @pure @ghost def readPartialBytePure(nBits: Int): (BitStream, UByte) = { require(nBits >= 1 && nBits < NO_OF_BITS_IN_BYTE) - require(validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) val cpy = snapshot(this) val b = cpy.readPartialByte(nBits) (cpy, b) } + @opaque @inlineOnce def checkBitPatternPresent(bit_terminated_pattern: Array[UByte], nBits: Long): Boolean = { require(nBits >= 0) - require(validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, nBits)) val tmpByte = currentByte val tmpBit = currentBit @@ -938,8 +1765,24 @@ case class BitStream private [asn1scala]( // TODO: The C code does indeed not reset the stream to the original position // in case we return 0 or 1, but doesn't it make sense to do so? // if !ret then - currentByte = tmpByte - currentBit = tmpBit + + ghostExpr(check(BitStream.invariant(currentBit, currentByte, buf.length))) + + // SAM: Here the issue is that the 2 assignments are not atomic, so the invariant can be temporarily violated + // For this reason it'd be better to have it as pre- and post condition everywhere rather than relying on the `require` + // Otherwise, we could store currentByte and currentBit in a tuple + if(tmpByte == this.buf.length) { + ghostExpr({ + check(this.currentBit == 0) + check(tmpBit == 0) + check(BitStream.invariant(tmpBit, currentByte, buf.length)) + }) + currentBit = tmpBit + currentByte = tmpByte + } else { + currentByte = tmpByte + currentBit = tmpBit + } ret }.ensuring(_ => old(this) == this) @@ -994,17 +1837,27 @@ case class BitStream private [asn1scala]( // ************** Aligning functions ********* def alignToByte(): Unit = { - require(validate_offset_bits( + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, (NO_OF_BITS_IN_BYTE - currentBit) & (NO_OF_BITS_IN_BYTE - 1) )) if currentBit != 0 then currentBit = 0 currentByte += 1 + }.ensuring(_ => this.buf == old(this).buf && BitStream.bitIndex(this.buf.length, this.currentByte, this.currentBit) <= BitStream.bitIndex(old(this).buf.length, old(this).currentByte, old(this).currentBit) + 7) + + @pure @ghost + def withAlignedByte(): BitStream = { + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, + (NO_OF_BITS_IN_BYTE - currentBit) & (NO_OF_BITS_IN_BYTE - 1) + )) + val cpy = snapshot(this) + cpy.alignToByte() + cpy } def alignToShort(): Unit = { - require(validate_offset_bits( + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, (NO_OF_BITS_IN_SHORT - // max alignment (16) - (NO_OF_BITS_IN_BYTE * (currentByte & (NO_OF_BYTES_IN_JVM_SHORT - 1)) + currentBit) // current pos ) & (NO_OF_BITS_IN_SHORT - 1)) // edge case (0,0) -> 0 @@ -1015,7 +1868,7 @@ case class BitStream private [asn1scala]( } def alignToInt(): Unit = { - require(validate_offset_bits( + require(BitStream.validate_offset_bits(buf.length.toLong, currentByte.toLong, currentBit.toLong, (NO_OF_BITS_IN_INT - // max alignment (32) - (NO_OF_BITS_IN_BYTE * (currentByte & (NO_OF_BYTES_IN_JVM_INT - 1)) + currentBit) // current pos ) & (NO_OF_BITS_IN_INT - 1)) // edge case (0,0) -> 0 diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec.scala index 7cbf7dfb5..f99f73b5d 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec.scala @@ -7,6 +7,8 @@ import stainless.annotation.* import stainless.proof.* import stainless.math.* import StaticChecks.{require as staticRequire, _} +import scala.annotation.static +import scala.annotation.newMain val masks2: Array[Int] = Array( 0x00000000, // 0 / 0000 0000 0000 0000 0000 0000 0000 0000 / 0x0000 0000 @@ -22,6 +24,9 @@ val CHAR_ZERO: Byte = 48 val CHAR_NINE: Byte = 57 val CHAR_0000: Byte = 0 +@extern +def assume(b: Boolean): Unit = {}.ensuring(_ => b) + /***********************************************************************************************/ /** Byte Stream Functions **/ /***********************************************************************************************/ @@ -54,6 +59,92 @@ def BitString_equal(arr1: Array[UByte], arr2: Array[UByte]): Boolean = { arraySameElements(arr1, arr2) } +object Codec { + import BitStream.{reader => _, *} + + @ghost @pure + def reader(w1: Codec, w2: Codec): (Codec, Codec) = { + require(w1.bitStream.isPrefixOf(w2.bitStream)) + val (r1, r2) = BitStream.reader(w1.bitStream, w2.bitStream) + (Codec(r1), Codec(r2)) + } + + // For showing invertibility of encoding - not fully integrated yet + /* + @ghost @pure + def decodeUnconstrainedWholeNumber_prefixLemma_helper(c1: Codec, c2: Codec): (Codec, Codec, Long, Codec, Long) = { + require(c1.bufLength() == c2.bufLength()) + require(BitStream.validate_offset_bytes(c1.bitStream.buf.length.toLong, c1.bitStream.currentByte.toLong, c1.bitStream.currentBit.toLong,1)) + val nBytes = c1.bitStream.readBytePure()._2.unsignedToInt + require(0 <= nBytes && nBytes <= 8) + require(BitStream.validate_offset_bytes(c1.bitStream.buf.length.toLong, c1.bitStream.currentByte.toLong, c1.bitStream.currentBit.toLong,1 + nBytes)) + require(arrayBitRangesEq( + c1.bitStream.buf, + c2.bitStream.buf, + 0, + BitStream.bitIndex(c1.bitStream.buf.length, c1.bitStream.currentByte, c1.bitStream.currentBit) + 8 + nBytes * 8 + )) + + val c2Reset = c2.resetAt(c1) + val (c1Res, l1) = c1.decodeUnconstrainedWholeNumberPure() + validateOffsetBytesContentIrrelevancyLemma(c1.bitStream, c2.bitStream.buf, 1 + nBytes) + readByteRangesEq(c1.bitStream, c2.bitStream, BitStream.bitIndex(c1.bitStream.buf.length, c1.bitStream.currentByte, c1.bitStream.currentBit) + 8 + nBytes * 8) + val (c2Res, l2) = c2Reset.decodeUnconstrainedWholeNumberPure() + (c2Reset, c1Res, l1, c2Res, l2) + } + + @ghost @pure @opaque @inlineOnce + def decodeUnconstrainedWholeNumber_prefixLemma(c1: Codec, c2: Codec): Unit = { + require(c1.bufLength() == c2.bufLength()) + require(BitStream.validate_offset_bytes(c1.bitStream.buf.length.toLong, c1.bitStream.currentByte.toLong, c1.bitStream.currentBit.toLong,1)) + val nBytes = c1.bitStream.readBytePure()._2.unsignedToInt + require(0 <= nBytes && nBytes <= 8) + require(BitStream.validate_offset_bytes(c1.bitStream.buf.length.toLong, c1.bitStream.currentByte.toLong, c1.bitStream.currentBit.toLong,1 + nBytes)) + require(arrayBitRangesEq( + c1.bitStream.buf, + c2.bitStream.buf, + 0, + BitStream.bitIndex(c1.bitStream.buf.length, c1.bitStream.currentByte, c1.bitStream.currentBit) + 8 + nBytes * 8 + )) + + val (c2Reset, c1Res, l1, c2Res, l2) = decodeUnconstrainedWholeNumber_prefixLemma_helper(c1, c2) + + { + val (c1_2, nBytes1) = c1.bitStream.readBytePure() + val (c2_2, nBytes2) = c2Reset.bitStream.readBytePure() + assert(nBytes1 == nBytes2) + readNLeastSignificantBitsPrefixLemma(c1_2, c2_2, nBytes1.unsignedToInt * 8) + }.ensuring { _ => + l1 == l2 && BitStream.bitIndex(c1Res.bitStream.buf.length, c1Res.bitStream.currentByte, c1Res.bitStream.currentBit) == BitStream.bitIndex(c2Res.bitStream.buf.length, c2Res.bitStream.currentByte, c2Res.bitStream.currentBit) + } + } + + @ghost @pure @opaque @inlineOnce + def decodeConstrainedPosWholeNumber_prefixLemma(c1: Codec, c2: Codec, min: ULong, max: ULong): Unit = { + require(c1.bufLength() == c2.bufLength()) + require(min <= max) + val nBits = GetBitCountUnsigned(max - min) + require(BitStream.validate_offset_bits(c1.bitStream.buf.length, c1.bitStream.currentByte, c1.bitStream.currentBit, nBits)) + require(arrayBitRangesEq( + c1.bitStream.buf, + c2.bitStream.buf, + 0, + BitStream.bitIndex(c1.bitStream.buf.length, c1.bitStream.currentByte, c1.bitStream.currentBit) + nBits + )) + + val c2Reset = c2.resetAt(c1) + val (c1Res, l1) = c1.decodeConstrainedPosWholeNumberPure(min, max) + val (c2Res, l2) = c2Reset.decodeConstrainedPosWholeNumberPure(min, max) + + { + readNLeastSignificantBitsPrefixLemma(c1.bitStream, c2.bitStream, nBits) + }.ensuring { _ => + l1 == l2 && BitStream.bitIndex(c1Res.bitStream.buf.length, c1Res.bitStream.currentByte, c1Res.bitStream.currentBit) == BitStream.bitIndex(c2Res.bitStream.buf.length, c2Res.bitStream.currentByte, c2Res.bitStream.currentBit) + } + } + */ +} + /** * Base class for the PER Codec that is used by ACN and UPER * @@ -61,6 +152,33 @@ def BitString_equal(arr1: Array[UByte], arr2: Array[UByte]): Boolean = { * */ case class Codec private [asn1scala](bitStream: BitStream) { + import Codec.* + import BitStream.{reader => _, *} + export bitStream.{resetAt => _, withMovedByteIndex => _, withMovedBitIndex => _, isPrefixOf => _, *} + + @ghost @pure @inline + def resetAt(other: Codec): Codec = { + require(bitStream.buf.length == other.bitStream.buf.length) + Codec(bitStream.resetAt(other.bitStream)) + } + + @ghost @pure @inline + def withMovedByteIndex(diffInBytes: Int): Codec = { + require(moveByteIndexPrecond(bitStream, diffInBytes)) + Codec(bitStream.withMovedByteIndex(diffInBytes)) + } + + @ghost @pure @inline + def withMovedBitIndex(diffInBits: Int): Codec = { + require(moveBitIndexPrecond(bitStream, diffInBits)) + Codec(bitStream.withMovedBitIndex(diffInBits)) + } + + @pure @inline + def bufLength(): Int = bitStream.buf.length + + @pure @inline + def isPrefixOf(codec2: Codec): Boolean = bitStream.isPrefixOf(codec2.bitStream) /** ******************************************************************************************** */ /** ******************************************************************************************** */ @@ -78,10 +196,20 @@ case class Codec private [asn1scala](bitStream: BitStream) { * @param v value that gets encoded * */ + @opaque @inlineOnce def encodeUnsignedInteger(v: ULong): Unit = { - require(bitStream.validate_offset_bits(GetBitCountUnsigned(v))) - + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,GetBitCountUnsigned(v))) appendNLeastSignificantBits(v.toRaw, GetBitCountUnsigned(v)) + } .ensuring { _ => + val w1 = old(this) + val w2 = this + val nBits = GetBitCountUnsigned(v) + w1.bitStream.buf.length == w2.bitStream.buf.length && BitStream.bitIndex(w2.bitStream.buf.length, w2.bitStream.currentByte, w2.bitStream.currentBit) == BitStream.bitIndex(w1.bitStream.buf.length, w1.bitStream.currentByte, w1.bitStream.currentBit) + nBits /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1.bitStream, w2.bitStream.buf, nBits) + val (r2Got, vGot) = r1.decodeUnsignedIntegerPure(nBits) + vGot == v && r2Got == r2 + }*/ } /** @@ -91,11 +219,22 @@ case class Codec private [asn1scala](bitStream: BitStream) { * @return Unsigned integer with nBits decoded from bitstream. * */ + @opaque @inlineOnce def decodeUnsignedInteger(nBits: Int): ULong = { require(nBits >= 0 && nBits <= NO_OF_BITS_IN_LONG) - require(bitStream.validate_offset_bits(nBits)) + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBits)) - readNLeastSignificantBits(nBits).toRawULong + ULong.fromRaw(readNLeastSignificantBits(nBits)) + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(this.bitStream.buf.length, this.bitStream.currentByte, this.bitStream.currentBit) == BitStream.bitIndex(old(this).bitStream.buf.length, old(this).bitStream.currentByte, old(this).bitStream.currentBit) + nBits) + + @ghost @pure + def decodeUnsignedIntegerPure(nBits: Int): (Codec, ULong) = { + require(nBits >= 0 && nBits <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBits)) + + val cpy = snapshot(this) + val res = cpy.decodeUnsignedInteger(nBits) + (cpy, res) } /** @@ -112,26 +251,39 @@ case class Codec private [asn1scala](bitStream: BitStream) { * v, min and max get interpreted as unsigned numbers. * */ + @opaque @inlineOnce def encodeConstrainedPosWholeNumber(v: ULong, min: ULong, max: ULong): Unit = { require(min <= max) require(min <= v) require(v <= max) - val range = max - min - if range == 0.toRawULong then - return - // get number of bits that get written val nRangeBits: Int = GetBitCountUnsigned(range) - - // get value that gets written - val encVal = v - min - - @ghost val nEncValBits = GetBitCountUnsigned(encVal) - assert(nRangeBits >= nEncValBits) - assert(bitStream.validate_offset_bits(nRangeBits)) - - appendNLeastSignificantBits(encVal, nRangeBits) + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nRangeBits)) + + if range != 0.toRawULong then + // get value that gets written + val encVal = v - min + + @ghost val nEncValBits = GetBitCountUnsigned(encVal) + // assert(nRangeBits >= nEncValBits) // TODO: T.O + + appendNLeastSignificantBits(encVal, nRangeBits) + // else + // ghostExpr { + // validReflexiveLemma(bitStream) + // } + }.ensuring { _ => + val w1 = old(this) + val w2 = this + val range = max - min + val nBits = GetBitCountUnsigned(range) + w1.bitStream.buf.length == w2.bitStream.buf.length && BitStream.bitIndex(w2.bitStream.buf.length, w2.bitStream.currentByte, w2.bitStream.currentBit) == BitStream.bitIndex(w1.bitStream.buf.length, w1.bitStream.currentByte, w1.bitStream.currentBit) + nBits /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1.bitStream, w2.bitStream.buf, nBits) + val (r2Got, vGot) = r1.decodeConstrainedPosWholeNumberPure(min, max) + vGot == v && r2Got == r2 + }*/ } /** @@ -145,25 +297,38 @@ case class Codec private [asn1scala](bitStream: BitStream) { * The returned value must be interpreted as an unsigned 64bit integer * */ + @opaque @inlineOnce def decodeConstrainedPosWholeNumber(min: ULong, max: ULong): ULong = { require(min <= max) staticRequire( - bitStream.validate_offset_bits(GetBitCountUnsigned(max - min)) + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,GetBitCountUnsigned(max - min)) ) val range: ULong = max - min // only one possible number if range == ULong.fromRaw(0) then - return min + min + else + val nRangeBits: Int = GetBitCountUnsigned(range) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nRangeBits)) + val decVal = decodeUnsignedInteger(nRangeBits) - val nRangeBits: Int = GetBitCountUnsigned(range) - assert(bitStream.validate_offset_bits(nRangeBits)) - val decVal = decodeUnsignedInteger(nRangeBits) + // assert(min + decVal <= max) // TODO: T.O + + (min + decVal): ULong + }.ensuring(_ => buf == old(this).buf && BitStream.bitIndex(this.bitStream.buf.length, this.bitStream.currentByte, this.bitStream.currentBit) == BitStream.bitIndex(old(this).bitStream.buf.length, old(this).bitStream.currentByte, old(this).bitStream.currentBit) + GetBitCountUnsigned(max - min)) - assert(min + decVal <= max) + @ghost @pure + def decodeConstrainedPosWholeNumberPure(min: ULong, max: ULong): (Codec, ULong) = { + staticRequire(min <= max) + staticRequire( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,GetBitCountUnsigned(max - min)) + ) - min + decVal + val cpy = snapshot(this) + val res = cpy.decodeConstrainedPosWholeNumber(min, max) + (cpy, res) } /** @@ -177,25 +342,42 @@ case class Codec private [asn1scala](bitStream: BitStream) { * @param max upper boundary of range * */ + @opaque @inlineOnce def encodeConstrainedWholeNumber(v: Long, min: Long, max: Long): Unit = { require(min <= max) require(min <= v && v <= max) - + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong))) // SAM There was a bug here, we checked for N bytes even though the number returned by teh function is bits val range: Long = stainless.math.wrapping(max - min) - if range == 0 then - return - // get number of bits that get written val nRangeBits: Int = GetBitCountUnsigned(range.toRawULong) - // get value that gets written - val encVal = stainless.math.wrapping(v - min).toRawULong - - @ghost val nEncValBits = GetBitCountUnsigned(encVal) - assert(nRangeBits >= nEncValBits) - assert(bitStream.validate_offset_bits(nRangeBits)) - - appendNLeastSignificantBits(encVal, nRangeBits) + if range != 0 then + // get value that gets written + val encVal = stainless.math.wrapping(v - min).toRawULong + + @ghost val nEncValBits = GetBitCountUnsigned(encVal) + //SAMassert(nRangeBits >= nEncValBits) + //SAMassert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nRangeBits)) + + appendNLeastSignificantBits(encVal, nRangeBits) + // else + // ghostExpr { + // validReflexiveLemma(bitStream) + // } + }.ensuring { _ => + val w1 = old(this) + val w2 = this + val range = stainless.math.wrapping(max - min) + val nBits = GetBitCountUnsigned(range.toRawULong) + w1.bitStream.buf.length == w2.bitStream.buf.length + && BitStream.bitIndex(w2.bitStream.buf.length, w2.bitStream.currentByte, w2.bitStream.currentBit) == BitStream.bitIndex(w1.bitStream.buf.length, w1.bitStream.currentByte, w1.bitStream.currentBit) + nBits /*&& + w1.isPrefixOf(w2) + && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1.bitStream, w2.bitStream.buf, nBits) + val (r2Got, vGot) = r1.decodeConstrainedWholeNumberPure(min, max) + vGot == v && r2Got == r2 + }*/ } /** @@ -210,12 +392,14 @@ case class Codec private [asn1scala](bitStream: BitStream) { * Remarks: * If the decoded data does not fulfill the range condition * this method will fail. + * SAM Changed to cap the value to the max/min value, so that the post condition holds * */ + @opaque @inlineOnce def decodeConstrainedWholeNumber(min: Long, max: Long): Long = { require(min <= max) staticRequire( - bitStream.validate_offset_bits( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) ) ) @@ -224,37 +408,80 @@ case class Codec private [asn1scala](bitStream: BitStream) { // only one possible value if range == 0 then - return min + min + else + val nRangeBits = GetBitCountUnsigned(range.toRawULong) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nRangeBits)) + val decVal = readNLeastSignificantBits(nRangeBits) - val nRangeBits = GetBitCountUnsigned(range.toRawULong) - assert(bitStream.validate_offset_bits(nRangeBits)) - val decVal = readNLeastSignificantBits(nRangeBits) + // assert(min + decVal <= max) // TODO: Invalid - assert(min + decVal <= max) + val res = stainless.math.wrapping(min + decVal) // TODO: Overflows but seems fine? + if res > max then + max + else if res < min then + min + else + res + } ensuring( res => + buf == old(this).buf && + res >= min && res <= max && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + BitStream.bitIndex(this.bitStream.buf.length, this.bitStream.currentByte, this.bitStream.currentBit) == BitStream.bitIndex(old(this).bitStream.buf.length, old(this).bitStream.currentByte, old(this).bitStream.currentBit) + GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) + ) + + @ghost @pure + def decodeConstrainedWholeNumberPure(min: Long, max: Long): (Codec, Long) = { + staticRequire(min <= max) + staticRequire( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, + GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) + ) + ) - min + decVal + val cpy = snapshot(this) + val res = cpy.decodeConstrainedWholeNumber(min, max) + (cpy, res) } + def decodeConstrainedWholeNumberInt(min: Int, max: Int): Int = { require(min <= max) + staticRequire( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, + GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) + ) + ) val i = decodeConstrainedWholeNumber(min, max).cutToInt - assert(i >= min &&& i <= max) + // assert(i >= min &&& i <= max) i } + def decodeConstrainedWholeNumberShort(min: Short, max: Short): Short = { require(min <= max) + staticRequire( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, + GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) + ) + ) val s = decodeConstrainedWholeNumber(min, max).cutToShort - assert(s >= min &&& s <= max) + // assert(s >= min &&& s <= max) s } + def decodeConstrainedWholeNumberByte(min: Byte, max: Byte): Byte = { require(min <= max) + staticRequire( + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, + GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong) + ) + ) val b = decodeConstrainedWholeNumber(min, max).cutToByte - assert(b >= min &&& b <= max) + // assert(b >= min &&& b <= max) b } @@ -268,9 +495,10 @@ case class Codec private [asn1scala](bitStream: BitStream) { * @param min lower boundary of range * */ + @opaque @inlineOnce def encodeSemiConstrainedWholeNumber(v: Long, min: Long): Unit = { require(min <= v) - staticRequire(bitStream.validate_offset_bytes( + staticRequire(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetLengthForEncodingUnsigned(stainless.math.wrapping(v - min).toRawULong) + 1) ) @@ -278,13 +506,14 @@ case class Codec private [asn1scala](bitStream: BitStream) { val nBytes = GetLengthForEncodingUnsigned(encV).toByte // need space for length and value - assert(bitStream.validate_offset_bytes(nBytes + 1)) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes + 1)) // encode length appendByte(nBytes.toRawUByte) // encode value appendNLeastSignificantBits(encV.toRaw, nBytes * NO_OF_BITS_IN_BYTE) - } + }.ensuring(_ => buf.length == old(this).buf.length && + BitStream.bitIndex(this.bitStream.buf.length, this.bitStream.currentByte, this.bitStream.currentBit) == BitStream.bitIndex(old(this).bitStream.buf.length, old(this).bitStream.currentByte, old(this).bitStream.currentBit) + GetLengthForEncodingUnsigned(stainless.math.wrapping(v - min).toRawULong) * 8L + 8L) /** * Decode number from bitstream that is in range [min, Long.MaxValue]. @@ -295,17 +524,30 @@ case class Codec private [asn1scala](bitStream: BitStream) { * */ def decodeSemiConstrainedWholeNumber(min: Long): Long = { - require(bitStream.validate_offset_bytes(1)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) // decode length val nBytes = readByte() // check bitstream precondition - assert(bitStream.validate_offset_bytes(nBytes.toRaw)) + // assert(nBytes.toRaw > 0) + // assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes.toRaw)) // SAM Cannot be proven now. // decode number - val v: ULong = readNLeastSignificantBits(nBytes.toRaw * NO_OF_BITS_IN_BYTE).toRawULong + // SAM: without an invariant here, it is impossible to prove that nBytes <= 8, so we need + // an guard here. + val nBytesRaw = nBytes.toRaw + val nBits = nBytesRaw * NO_OF_BITS_IN_BYTE + // SAM GUARD + val v: ULong = if(!(nBits >= 0 && nBits <= 64) || !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nBits)){ + 0L.toRawULong + } else { + readNLeastSignificantBits(nBits).toRawULong + } + + // SAM: here the post condition should be obvious, as ULong are always positive. But we can have + // overflow, and ULong does not encode the unsigned nature in any way, so cannot work. v + min - }.ensuring(x => x >= min) + }// SAM .ensuring(x => x >= min) /** * Encode number to the bitstream within the range [min, Long.Max_Value]. @@ -318,7 +560,7 @@ case class Codec private [asn1scala](bitStream: BitStream) { */ def encodeSemiConstrainedPosWholeNumber(v: ULong, min: ULong): Unit = { require(min <= v) - staticRequire(bitStream.validate_offset_bytes( + staticRequire(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetLengthForEncodingUnsigned(stainless.math.wrapping(v - min)) + 1) ) @@ -326,7 +568,7 @@ case class Codec private [asn1scala](bitStream: BitStream) { val nBytes = GetLengthForEncodingUnsigned(encV.toRawULong).toByte /* need space for length and value */ - assert(bitStream.validate_offset_bytes(nBytes + 1)) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes + 1)) /* encode length */ appendByte(nBytes.toRawUByte) @@ -342,17 +584,24 @@ case class Codec private [asn1scala](bitStream: BitStream) { * */ def decodeSemiConstrainedPosWholeNumber(min: ULong): ULong = { - require(bitStream.validate_offset_bytes(1)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) // decode length val nBytes = readByte() // check bitstream precondition - assert(bitStream.validate_offset_bytes(nBytes.toRaw)) + // SAM assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes.toRaw)) // decode number - val v = readNLeastSignificantBits(nBytes.toRaw * NO_OF_BITS_IN_BYTE) - val res = ULong.fromRaw(v + min) // For some reasons, the scala compiler chokes on this being returned + val nBytesRaw = nBytes.toRaw + val nBits = nBytesRaw * NO_OF_BITS_IN_BYTE + // SAM GUARD + val v = if(!(nBits >= 0 && nBits <= 64) || !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nBits)){ + 0L.toRawULong + } else { + readNLeastSignificantBits(nBits).toRawULong + } + val res: ULong = ULong.fromRaw(v + min) // For some reasons, the scala compiler chokes on this being returned res - }.ensuring(x => min <= x) + }//.ensuring(res => min <= res) /** * 8.3 Encoding of an integer value @@ -362,21 +611,50 @@ case class Codec private [asn1scala](bitStream: BitStream) { * * @param v The value that is always encoded in the smallest possible number of octets. */ + @opaque @inlineOnce def encodeUnconstrainedWholeNumber(v: Long): Unit = { staticRequire( - bitStream.validate_offset_bytes(1 + GetLengthForEncodingSigned(v)) + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1 + GetLengthForEncodingSigned(v)) ) // call func that fulfills 8.3.2 val nBytes: Int = GetLengthForEncodingSigned(v) - + val nBits = nBytes * NO_OF_BITS_IN_BYTE // need space for length and value - assert(bitStream.validate_offset_bytes(nBytes + 1)) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes + 1)) + @ghost val this1 = snapshot(this) // encode number - single octet appendByte(nBytes.toByte.toRawUByte) + + @ghost val this2 = snapshot(this) // encode number - appendNLeastSignificantBits(v, nBytes * NO_OF_BITS_IN_BYTE) + appendNLeastSignificantBits(v & onesLSBLong(nBits), nBits) + /* + ghostExpr { + validTransitiveLemma(this1.bitStream, this2.bitStream, this.bitStream) + val this2Reset = this2.bitStream.resetAt(this1.bitStream) + readBytePrefixLemma(this2Reset, this.bitStream) + assert(this2.bitStream.resetAt(this1.bitStream).readBytePure()._2.unsignedToInt == nBytes) + val (r1, r2) = reader(this1, this) + validateOffsetBytesContentIrrelevancyLemma(this1.bitStream, this.bitStream.buf, nBytes + 1) + assert(r1 == Codec(BitStream(snapshot(this.bitStream.buf), this1.bitStream.currentByte, this1.bitStream.currentBit))) + assert(BitStream.validate_offset_bytes(r1.bitStream.buf.length, r1.bitStream.currentByte, r1.bitStream.currentBit, nBytes + 1)) + val (r2Got, vGot) = r1.decodeUnconstrainedWholeNumberPure() + check(r2Got == r2) + //SAM assert((vGot & onesLSBLong(nBits)) == (v & onesLSBLong(nBits))) + check(vGot == v) + }*/ + }.ensuring { _ => + val w1 = old(this) + val w2 = this + val nBits = NO_OF_BITS_IN_BYTE + GetLengthForEncodingSigned(v) * NO_OF_BITS_IN_BYTE + w1.bitStream.buf.length == w2.bitStream.buf.length && BitStream.bitIndex(w2.bitStream.buf.length, w2.bitStream.currentByte, w2.bitStream.currentBit) == BitStream.bitIndex(w1.bitStream.buf.length, w1.bitStream.currentByte, w1.bitStream.currentBit) + nBits /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = reader(w1, w2) + validateOffsetBitsContentIrrelevancyLemma(w1.bitStream, w2.bitStream.buf, nBits) + val (r2Got, vGot) = r1.decodeUnconstrainedWholeNumberPure() + vGot == v && r2Got == r2 + }*/ } /** @@ -388,24 +666,64 @@ case class Codec private [asn1scala](bitStream: BitStream) { * * @return decoded number */ + @opaque @inlineOnce def decodeUnconstrainedWholeNumber(): Long = { - require(bitStream.validate_offset_bytes(1)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) // get length - val nBytes = readByte() - // check bitstream precondition - assert(bitStream.validate_offset_bytes(nBytes.toRaw)) - // read value - readNLeastSignificantBits(nBytes.toRaw * NO_OF_BITS_IN_BYTE) + val nBytes = readByte().unsignedToInt + if (!(0 <= nBytes && nBytes <= 8 && BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nBytes))) + 0L + else + val nBits = nBytes * NO_OF_BITS_IN_BYTE + // check bitstream precondition + //SAM assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nBytes)) + //SAM assert(0 <= nBytes && nBytes <= 8) + // read value + val read = readNLeastSignificantBits(nBits) + // TODO: This was added (sign extension) + if (read == 0 || nBits == 0 || nBits == 64 || (read & (1L << (nBits - 1))) == 0L) read + else onesMSBLong(64 - nBits) | read + }.ensuring(_ => bitStream.buf == old(this).bitStream.buf && bitIndex <= old(this).bitIndex + 72L) + + @ghost @pure + def decodeUnconstrainedWholeNumberPure(): (Codec, Long) = { + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) + staticRequire { + val nBytes = bitStream.readBytePure()._2.unsignedToInt + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1 + nBytes) && 0 <= nBytes && nBytes <= 8 + } + val cpy = snapshot(this) + val res = cpy.decodeUnconstrainedWholeNumber() + (cpy, res) } /** * Facade function for real encoding - * @param vVal real input in IEEE754 double format + * @param vValDouble real input in IEEE754 double format */ @extern - def encodeReal(vVal: Double): Unit = { - encodeRealBitString(java.lang.Double.doubleToRawLongBits(vVal)) + def encodeReal(vValDouble: Double): Unit = { + val vVal = java.lang.Double.doubleToRawLongBits(vValDouble) + require({ + val rawExp = (vVal & ExpoBitMask) >>> DoubleNoOfMantissaBits + rawExp >= 0 &&& rawExp <= ((1 << 11) - 2) // 2046, 2047 is the infinity case - never end up here with infinity + }) + require({ + val (exponent, mantissa) = CalculateMantissaAndExponent(vVal) + val nManLen: Int = GetLengthForEncodingUnsigned(mantissa) + val compactExp = RemoveLeadingFFBytesIfNegative(exponent.toRaw) + val nExpLen: Int = GetLengthForEncodingUnsigned(compactExp.toLong.toRawULong) + nExpLen >= 1 && nExpLen <= 2 && nManLen <= 7 && + (if (vVal == DoublePosZeroBitString ) then + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8) + else if (vVal == DoubleNegZeroBitString || (vVal & ExpoBitMask) == ExpoBitMask) then + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 16) + else + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 16 + nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE) + ) + }) + encodeRealBitString(vVal) } /** @@ -435,86 +753,144 @@ case class Codec private [asn1scala](bitStream: BitStream) { * */ private def encodeRealBitString(vVal: Long): Unit = { + // Require from CalculateMantissaAndExponent + require({ + val rawExp = (vVal & ExpoBitMask) >>> DoubleNoOfMantissaBits + rawExp >= 0 &&& rawExp <= ((1 << 11) - 2) // 2046, 2047 is the infinity case - never end up here with infinity + }) + require({ + val (exponent, mantissa) = CalculateMantissaAndExponent(vVal) + val nManLen: Int = GetLengthForEncodingUnsigned(mantissa) + val compactExp = RemoveLeadingFFBytesIfNegative(exponent.toRaw) + val nExpLen: Int = GetLengthForEncodingUnsigned(compactExp.toLong.toRawULong) + nExpLen >= 1 && nExpLen <= 2 && nManLen <= 7 && + (if (vVal == DoublePosZeroBitString ) then + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8) + else if (vVal == DoubleNegZeroBitString || (vVal & ExpoBitMask) == ExpoBitMask) then + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 16) + else + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 16 + nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE) + ) + }) // according to T-REC-X.690 2021 + check(GetBitCountUnsigned(ULong.fromRaw(0xFF)) == 8) + var v = vVal // 8.5.2 Plus Zero if v == DoublePosZeroBitString then + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8)) encodeConstrainedWholeNumber(0, 0, 0xFF) - return; + // 8.5.3 Minus Zero - if v == DoubleNegZeroBitString then + else if v == DoubleNegZeroBitString then + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,16)) encodeConstrainedWholeNumber(1, 0, 0xFF) + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8)) encodeConstrainedWholeNumber(0x43, 0, 0xFF) - return; + // 8.5.9 SpecialRealValues - if (v & ExpoBitMask) == ExpoBitMask then + else if (v & ExpoBitMask) == ExpoBitMask then // 8.5.9 PLUS-INFINITY if v == DoublePosInfBitString then + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,16)) encodeConstrainedWholeNumber(1, 0, 0xFF) + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8)) encodeConstrainedWholeNumber(0x40, 0, 0xFF) - return; // 8.5.9 MINUS-INFINITY else if v == DoubleNegInfBitString then + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,16)) encodeConstrainedWholeNumber(1, 0, 0xFF) + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8)) encodeConstrainedWholeNumber(0x41, 0, 0xFF) - return; // 8.5.9 NOT-A-NUMBER else + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,16)) encodeConstrainedWholeNumber(1, 0, 0xFF) + check( BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8)) encodeConstrainedWholeNumber(0x42, 0, 0xFF) - return; - - // 8.5.6 a) - // fixed encoding style to binary - // 8.5.7.2 exp has always base 2 - bit 0x20 and 0x10 are always 0 - // 8.5.7.3 F value is always zero - bit 0x08 and 0x04 are always 0 - var header = 0x80 - - // 8.5.7.1 - if ((v & SignBitMask) == SignBitMask) { // check sign bit - header |= 0x40 - v &= InverseSignBitMask // clear sign bit - } - - val (exponent, mantissa) = CalculateMantissaAndExponent(v) - - val nManLen: Int = GetLengthForEncodingUnsigned(mantissa) - assert(nManLen <= 7) // 52 bit - - val compactExp = RemoveLeadingFFBytesIfNegative(exponent.toRaw) - val nExpLen: Int = GetLengthForEncodingUnsigned(compactExp.toLong.toRawULong) - assert(nExpLen >= 1 && nExpLen <= 2) - - // 8.5.7.4 - if nExpLen == 2 then - header |= 0x01 - else if nExpLen == 3 then // this will never happen with this implementation - header |= 0x02 - - /* encode length */ - encodeConstrainedWholeNumber(1 + nExpLen + nManLen, 0, 0xFF) - - /* encode header */ - encodeConstrainedWholeNumber(header & 0xFF, 0, 0xFF) - - /* encode exponent */ - if exponent.toRaw >= 0 then - // fill with zeros to have a whole byte - appendNZeroBits(nExpLen * 8 - GetBitCountUnsigned(exponent.toULong)) - encodeUnsignedInteger(exponent.toULong) else - encodeUnsignedInteger(compactExp.toLong.toRawULong) - - /* encode mantissa */ - appendNZeroBits(nManLen * 8 - GetBitCountUnsigned(mantissa)) - encodeUnsignedInteger(mantissa) + // 8.5.6 a) + // fixed encoding style to binary + // 8.5.7.2 exp has always base 2 - bit 0x20 and 0x10 are always 0 + // 8.5.7.3 F value is always zero - bit 0x08 and 0x04 are always 0 + var header = 0x80 + + // 8.5.7.1 + if ((v & SignBitMask) == SignBitMask) { // check sign bit + header |= 0x40 + v &= InverseSignBitMask // clear sign bit + } + + val (exponent, mantissa) = CalculateMantissaAndExponent(v) + + val nManLen: Int = GetLengthForEncodingUnsigned(mantissa) + assert(nManLen <= 7) // 52 bit + + val compactExp = RemoveLeadingFFBytesIfNegative(exponent.toRaw) + val nExpLen: Int = GetLengthForEncodingUnsigned(compactExp.toLong.toRawULong) + assert(nExpLen >= 1 && nExpLen <= 2) + + // 8.5.7.4 + if nExpLen == 2 then + header |= 0x01 + else if nExpLen == 3 then // this will never happen with this implementation + header |= 0x02 + + /* encode length */ + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,16 + nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE) + + encodeConstrainedWholeNumber(1 + nExpLen + nManLen, 0, 0xFF) + + check(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8 + nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE)) + // /* encode header */ + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,8 + nManLen + nExpLen ) + + encodeConstrainedWholeNumber(header & 0xFF, 0, 0xFF) + + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nManLen + nExpLen ) + + // TODO this might be more complicated, because by removing the require in the bistream class, I'll in fact break the safety there + /* encode exponent */ + if exponent.toRaw >= 0 then + // fill with zeros to have a whole byte + val remaining = nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, remaining)) + val toFill = nExpLen * NO_OF_BITS_IN_BYTE - GetBitCountUnsigned(exponent.toULong) + val remainingAfter = remaining - toFill + @ghost val oldThis = snapshot(this) + appendNZeroBits(toFill) + ghostExpr { + BitStream.validateOffsetBitsIneqLemma(oldThis.bitStream, this.bitStream, remaining, toFill) + } + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, remainingAfter)) + assert(GetBitCountUnsigned(exponent.toULong) <= remainingAfter) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(exponent.toULong))) + encodeUnsignedInteger(exponent.toULong) + check(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nManLen * NO_OF_BITS_IN_BYTE )) + else + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nManLen * NO_OF_BITS_IN_BYTE + nExpLen * NO_OF_BITS_IN_BYTE)) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nManLen * NO_OF_BITS_IN_BYTE + GetBitCountUnsigned(compactExp.toLong.toRawULong))) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(compactExp.toLong.toRawULong))) + encodeUnsignedInteger(compactExp.toLong.toRawULong) + check(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nManLen * NO_OF_BITS_IN_BYTE )) + + /* encode mantissa */ + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nManLen * NO_OF_BITS_IN_BYTE )) + @ghost val bitIndexBeforeAppendingZeros = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) + val mantissaActualSize = GetBitCountUnsigned(mantissa) + val nZeros = nManLen * NO_OF_BITS_IN_BYTE - mantissaActualSize + appendNZeroBits(nZeros) + assert(BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) == bitIndexBeforeAppendingZeros + nZeros) + assert(nManLen * NO_OF_BITS_IN_BYTE - nZeros == mantissaActualSize) + check(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, mantissaActualSize)) + encodeUnsignedInteger(mantissa) } @@ -527,41 +903,67 @@ case class Codec private [asn1scala](bitStream: BitStream) { /** * Real decoding implementation according to the PER standard + * If the buffer is invalid (too short or malformed), has an undefined behaviour, but does not crash. * @return decoded double bits as 64 bit integer */ private def decodeRealBitString(): Long = { - require(bitStream.validate_offset_bytes(1)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) + // staticRequire({ + // val length = readBytePure()._2.toRaw + // length >= 0 + // && length != 1 // Otherwise there's only the space for the header SAM + // && length <= DoubleMaxLengthOfSentBytes + // && BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1 + length.toInt) + + // }) // get length val length = readByte().toRaw + if(length >= 0 + && length != 1 // Otherwise there's only the space for the header SAM + && length <= DoubleMaxLengthOfSentBytes + && BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1 + length.toInt)) then - // 8.5.2 PLUS-ZERO - if length == 0 then - return 0 + // 8.5.2 PLUS-ZERO + if length == 0 then + return 0 - // sanity check - assert(length > 0 && length <= DoubleMaxLengthOfSentBytes) + // sanity check + assert(length > 0 && length <= DoubleMaxLengthOfSentBytes) - // get value - assert(bitStream.validate_offset_bytes(1)) - val header = readByte().toRaw - assert((header.unsignedToInt & 0x80) == 0x80, "only binary mode supported") + // get value + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) + val header = readByte().toRaw - // 8.5.9 PLUS-INFINITY - if header == 0x40 then - DoublePosInfBitString - // 8.5.9 MINUS-INFINITY - else if header == 0x41 then - DoubleNegInfBitString - // 8.5.9 NOT-A-NUMBER - else if header == 0x42 then - DoubleNotANumber - // 8.5.3 MINUS-ZERO - else if header == 0x43 then - DoubleNegZeroBitString - // Decode 8.5.7 + // SAM here I don't think we should require that, but more exit if + // that's not the case, but we can discuss + + if((header.unsignedToInt & 0x80) != 0x80) then + // "only binary mode supported" + 0L + else + // 8.5.9 PLUS-INFINITY + if header == 0x40 then + DoublePosInfBitString + // 8.5.9 MINUS-INFINITY + else if header == 0x41 then + DoubleNegInfBitString + // 8.5.9 NOT-A-NUMBER + else if header == 0x42 then + DoubleNotANumber + // 8.5.3 MINUS-ZERO + else if header == 0x43 then + DoubleNegZeroBitString + // Decode 8.5.7 + else + check((header.unsignedToInt & 0x80) == 0x80) + // SAM GUARD + if((header.toRaw & 0x03) + 1 > length.toInt - 1) then + 0L + else + decodeRealFromBitStream(length.toInt - 1, header.toRawUByte) else - decodeRealFromBitStream(length.toInt - 1, header.toRawUByte) + 0L } /** @@ -569,14 +971,17 @@ case class Codec private [asn1scala](bitStream: BitStream) { * The exponent length and other details given in the header have be be * decoded before calling this function * + * If the buffer is invalid (too short or malformed), has an undefined behaviour, but does not crash. + * * @param lengthVal already decoded exponent length * @param header already decoded header * @return decoded real number as 64bit integer */ private def decodeRealFromBitStream(lengthVal: Int, header: UByte): Long = { require(lengthVal >= 1 && lengthVal < DoubleMaxLengthOfSentBytes) // without header byte + require((header.toRaw & 0x03) + 1 <= lengthVal) require((header.unsignedToInt & 0x80) == 0x80) - require(bitStream.validate_offset_bytes(lengthVal)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,lengthVal)) // 8.5.7.2 Base val expFactor: Int = header.unsignedToInt match @@ -584,189 +989,724 @@ case class Codec private [asn1scala](bitStream: BitStream) { case x if (x & 0x20) > 0 => 4 // 2^4 = 16 case _ => 1 // 2^1 = 2 + assert(expFactor == 1 || expFactor == 3 || expFactor == 4) + // 8.5.7.3 Factor F - val factor = 1 << ((header.toRaw & 0x0C) >>> 2) + val factor: Long = 1 << ((header.toRaw & 0x0C) >>> 2) + assert(factor <= 8) // 8.5.7.4 Length of Exponent val expLen = (header.toRaw & 0x03) + 1 + assert(expLen >= 1 && expLen <= 4) + // sanity check - assert(expLen <= lengthVal) + assert(expLen <= lengthVal) // TODO for the substraction overflow below // decode exponent var exponent: Int = if peekBit() then 0xFF_FF_FF_FF else 0 + assert(exponent == 0 || exponent == -1) + + check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,lengthVal)) var i: Int = 0 (while i < expLen do decreases(expLen - i) + check(i < expLen && lengthVal - i > 0) + check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,lengthVal - i)) + check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,1)) exponent = exponent << 8 | (readByte().toRaw.toInt & 0xFF) i += 1 - ).invariant(i >= 0 && i <= expLen) - - // decode mantissa parts - val length = lengthVal - expLen - var N: Long = 0 - var j: Int = 0 - (while j < length do - decreases(length - j) - - N = (N << 8) | (readByte().toRaw.toInt & 0xFF) + ).invariant(i >= 0 && i <= expLen && BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,lengthVal - i)) - j += 1 - ).invariant(j >= 0 && j <= length) + check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,lengthVal - expLen)) - var v: Long = GetDoubleBitStringByMantissaAndExp((N * factor).toLong.toRawULong, expFactor * exponent) + // SAM guard if for the exponent read from the bitstream + // assert(exponent < (Int.MaxValue / 4) && exponent >= -1) + if(exponent >= (Int.MaxValue / 4) || exponent <= -1) then + 0L + else + // decode mantissa parts + val length = lengthVal - expLen + var N: Long = 0 + var j: Int = 0 + (while j < length do + decreases(length - j) + + N = (N << 8) | (readByte().toRaw.toInt & 0xFF) + + j += 1 + ).invariant( + j >= 0 && + j <= length && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, length - j)) + + // assert(N < (Long.MaxValue / 8) && N >= 0) // TODO Check the doc to see if N has a max value, otherwise there is a bug here + // SAM guard if for the mantissa read from the bitstream + if(N >= (Long.MaxValue / 8) || N < 0) then + 0L + else + val x1: ULong = (N * factor).toRawULong + val x2: Int = expFactor * exponent + var v: Long = GetDoubleBitStringByMantissaAndExp(x1, x2) - // 8.5.7.1 Set Sign bit - if (header.toRaw & 0x40) > 0 then - v |= SignBitMask + // 8.5.7.1 Set Sign bit + if (header.toRaw & 0x40) > 0 then + v |= SignBitMask - v + v } def encodeOctetString_no_length(arr: Array[UByte], nCount: Int): Unit = { - require(bitStream.validate_offset_bytes(nCount)) + require(nCount >= 0 && nCount <= arr.length) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nCount)) appendByteArray(arr, nCount) } def decodeOctetString_no_length(nCount: Int): Array[UByte] = { require(nCount >= 0 && nCount <= Integer.MAX_VALUE / NO_OF_BITS_IN_BYTE) - require(bitStream.validate_offset_bytes(nCount)) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nCount)) readByteArray(nCount) } def encodeOctetString_fragmentation(arr: Array[UByte], nCount: Int) = { - require(nCount >= 0) + require(nCount >= 0 && nCount <= arr.length) + require(nCount < Int.MaxValue / 8 - 2 - (nCount / 0x4000) ) // To avoid overflow of the available length checks + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount + (nCount / 0x4000) + 2)) // Room for information bytes + data var nRemainingItemsVar1: Int = nCount var nCurBlockSize1: Int = 0 - var nCurOffset1: Int = 0 + var nCurOffset1: Int = 0 // Which represents the currently written bytes number SAM - while nRemainingItemsVar1 >= 0x4000 do - decreases(nRemainingItemsVar1) - if nRemainingItemsVar1 >= 0x10000 then - nCurBlockSize1 = 0x10000 - encodeConstrainedWholeNumber(0xC4, 0, 0xFF) - else if nRemainingItemsVar1 >= 0xC000 then - nCurBlockSize1 = 0xC000 - encodeConstrainedWholeNumber(0xC3, 0, 0xFF) - else if nRemainingItemsVar1 >= 0x8000 then - nCurBlockSize1 = 0x8000 - encodeConstrainedWholeNumber(0xC2, 0, 0xFF) - else - nCurBlockSize1 = 0x4000 - encodeConstrainedWholeNumber(0xC1, 0, 0xFF) + @ghost val bufLength = bitStream.buf.length + @ghost val bitIndexBeforeInnerWhile = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) + @ghost val currentByteBeforeInnerWhile = bitStream.currentByte + @ghost val currentBitBeforeInnerWhile = bitStream.currentBit + + val resInner = encodeOctetString_fragmentation_innerWhile(arr, nCount, 0, nRemainingItemsVar1, nCurOffset1, BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit )) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, resInner._1 + 2)) + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, resInner._1 + 2))) + + nRemainingItemsVar1 = resInner._1 + nCurOffset1 = resInner._2 - var i1: Int = nCurOffset1 - while i1 < nCurBlockSize1 + nCurOffset1 do - decreases(nCurBlockSize1 + nCurOffset1 - i1) - appendByte(arr(i1)) - i1 += 1 + assert(bufLength == bitStream.buf.length) - nCurOffset1 += nCurBlockSize1 - nRemainingItemsVar1 -= nCurBlockSize1 + @ghost val bitIndexAfterInnerWhile = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) + @ghost val currentByteAfterInnerWhile = bitStream.currentByte + @ghost val currentBitAfterInnerWhile = bitStream.currentBit + assert(bitIndexAfterInnerWhile <= bitIndexBeforeInnerWhile + (nCount / 0x4000) * 8 + nCount * 8 - nRemainingItemsVar1 * 8) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 2)) if nRemainingItemsVar1 <= 0x7F then + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + check(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8)) // == GetLengthForEncodingUnsigned(0xFF) encodeConstrainedWholeNumber(nRemainingItemsVar1.toLong, 0, 0xFF) + + @ghost val bufLengthAfterEncodingByte = bitStream.buf.length + @ghost val currentBitAfterEncodingByte = bitStream.currentBit + @ghost val currentByteAfterEncodingByte = bitStream.currentByte + @ghost val bitIndexAfterEncodingByte = BitStream.bitIndex(bufLength, currentByteAfterEncodingByte, currentBitAfterEncodingByte) + + assert(bufLengthAfterEncodingByte == bufLength) + assert(bitIndexAfterEncodingByte == bitIndexAfterInnerWhile + 8) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, currentByteAfterEncodingByte , currentBitAfterEncodingByte, nRemainingItemsVar1 + 1)) + assert(BitStream.bitIndex(bufLength, bitStream.currentByte, bitStream.currentBit) == bitIndexAfterInnerWhile + 8) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 1)) + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 1))) else + // SAM here we write 1000000000000000 (16 bits), to indicate that more than 128 elements remain + ghostExpr(check(BitStream.validate_offset_bits(bufLength, bitStream.currentByte, bitStream.currentBit, 1))) appendBit(true) + ghostExpr(lemmaGetBitCountUnsigned7FFFEquals15()) + assert(GetBitCountUnsigned(stainless.math.wrapping(0x7FFF).toRawULong) == 15) + assert(BitStream.bitIndex(bufLength, bitStream.currentByte, bitStream.currentBit) == bitIndexAfterInnerWhile + 1) + ghostExpr(check(BitStream.validate_offset_bits(bufLength, bitStream.currentByte, bitStream.currentBit, 15))) // == GetLengthForEncodingUnsigned(0x7FFF) + encodeConstrainedWholeNumber(nRemainingItemsVar1.toLong, 0, 0x7FFF) + assert(BitStream.bitIndex(bufLength, bitStream.currentByte, bitStream.currentBit) == bitIndexAfterInnerWhile + 16) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 )) + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 ))) + + assert(bufLength == bitStream.buf.length) + @ghost val bitIndexAfterLength = BitStream.bitIndex(bufLength, bitStream.currentByte, bitStream.currentBit) + @ghost val currentByteAfterLength = bitStream.currentByte + @ghost val currentBitAfterLength = bitStream.currentBit + + assert(bitIndexAfterLength <= bitIndexAfterInnerWhile + 16) + ghostExpr(check(BitStream.validate_offset_bytes(bufLength, currentByteAfterLength, currentBitAfterLength, nRemainingItemsVar1))) + + // var i1: Int = nCurOffset1 + // (while i1 < (nCurOffset1 + nRemainingItemsVar1) do + // decreases(nCurOffset1 + nRemainingItemsVar1 - i1) + // appendByte(arr(i1)) + // i1 += 1 + // ).invariant( + // nCurOffset1 + nRemainingItemsVar1 - i1 >= 0 && + // nCurOffset1 + nRemainingItemsVar1 - i1 <= nRemainingItemsVar1 && + // i1 <= nCount && + // i1 <= arr.length && + // BitStream.validate_offset_bytes(bufLength, currentByteAfterLength, currentBitAfterLength, nCurOffset1 + nRemainingItemsVar1 - i1) + // ) + + if(nRemainingItemsVar1 > 0) then + encodeOctetString_fragmentation_innerMostWhile(arr, nCurOffset1, nCurOffset1 + nRemainingItemsVar1, BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit )) + } + + def encodeOctetString_fragmentation_innerWhile(arr: Array[UByte], nCount: Int, @ghost currentlyWrittenBlocksOf0x4000: Int, nRemainingItemsVar1: Int, nCurOffset1: Int, bitIndex: Long ): (Int, Int) = { + require(nRemainingItemsVar1 >= 0) + staticRequire(currentlyWrittenBlocksOf0x4000 >= 0) + require(nCurOffset1 >= 0) + require(nCount >= 0) + require(nCount < Int.MaxValue - (nCount / 0x4000)) + require(nRemainingItemsVar1 < Int.MaxValue / 8) + require(nRemainingItemsVar1 < Int.MaxValue / 8 - 2 - (nRemainingItemsVar1 / 0x4000)) + require(nRemainingItemsVar1 <= nCount) + staticRequire(currentlyWrittenBlocksOf0x4000 < Int.MaxValue / 0x4000) // to avoid overflow + require(nCount <= arr.length) + staticRequire(nCount - currentlyWrittenBlocksOf0x4000 * 0x4000 == nRemainingItemsVar1) + staticRequire(nCurOffset1 == currentlyWrittenBlocksOf0x4000 * 0x4000) + require(BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) == bitIndex) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + (nRemainingItemsVar1 / 0x4000) + 2)) + + decreases(nRemainingItemsVar1) + + @ghost val bufferLength = bitStream.buf.length + + if (nRemainingItemsVar1 >= 0x4000) then + val nCurBlockSize1 = + if nRemainingItemsVar1 >= 0x10000 then + 0x10000 + else if nRemainingItemsVar1 >= 0xC000 then + 0xC000 + else if nRemainingItemsVar1 >= 0x8000 then + 0x8000 + else + 0x4000 + // Write to the buffer the block header and return the number of blocks of 0x4000 it would represent + val blockSize: Long = nCurBlockSize1 match { + case 0x10000 => + 0xC4 + case 0xC000 => + 0xC3 + case 0x8000 => + 0xC2 + case 0x4000 => + 0xC1 + } - var i1: Int = nCurOffset1 - (while i1 < (nCurOffset1 + nRemainingItemsVar1) do - decreases(nCurOffset1 + nRemainingItemsVar1 - i1) - appendByte(arr(i1)) - i1 += 1 - ).invariant(true) // TODO - } + val nNewBlocksOf0x4000 = blockSize match { + case 0xC4 => + 4 + case 0xC3 => + 3 + case 0xC2 => + 2 + case 0xC1 => + 1 + } + + @ghost val bitIndexBeforeHeader = BitStream.bitIndex(bufferLength, bitStream.currentByte, bitStream.currentBit ) + assert(GetBitCountUnsigned(0xFF.toRawULong) == 8) + + ghostExpr(check(bitIndexBeforeHeader == bitIndex)) + + encodeConstrainedWholeNumber(blockSize, 0, 0xFF) + + assert(bitStream.buf.length == bufferLength) + + + @ghost val bitIndexAfterHeader = BitStream.bitIndex(bufferLength, bitStream.currentByte, bitStream.currentBit ) + @ghost val currentByteAfterHeader = bitStream.currentByte + @ghost val currentBitAfterHeader = bitStream.currentBit + + assert(bitIndexBeforeHeader + NO_OF_BITS_IN_BYTE == bitIndexAfterHeader) + assert( bitIndexAfterHeader <= bitIndexBeforeHeader + 4 * NO_OF_BITS_IN_BYTE) + ghostExpr(check(( bitIndexAfterHeader <= bitIndexBeforeHeader + 4 * NO_OF_BITS_IN_BYTE))) + + val validatedOffset1: Int = nRemainingItemsVar1 + (nRemainingItemsVar1 / 0x4000) - 1 + 2 + + assert(BitStream.validate_offset_bytes(bufferLength, bitStream.currentByte, bitStream.currentBit, validatedOffset1)) + ghostExpr(check(BitStream.validate_offset_bytes(bufferLength, currentByteAfterHeader, currentBitAfterHeader, validatedOffset1))) + assert(BitStream.validate_offset_bytes(bufferLength,bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + (nRemainingItemsVar1 / 0x4000) - 1 + 2)) + + assert(nCount == nRemainingItemsVar1 + nCurOffset1) + assert(nRemainingItemsVar1 >= nCurBlockSize1) + assert(nCurOffset1 + nCurBlockSize1 <= nCount) + assert(nCurOffset1 + nCurBlockSize1 <= arr.length) + assert(nCurOffset1 + nCurBlockSize1 >= 0) + + encodeOctetString_fragmentation_innerMostWhile(arr, nCurOffset1, nCurOffset1 + nCurBlockSize1, BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit )) + + assert(bitStream.buf.length == bufferLength) + + @ghost val bitIndexAfterAppending = BitStream.bitIndex(bufferLength, bitStream.currentByte, bitStream.currentBit ) + @ghost val currentByteAfterAppending = bitStream.currentByte + @ghost val currentBitAfterAppending = bitStream.currentBit + + assert(bitIndexAfterAppending == bitIndexAfterHeader + nCurBlockSize1 * 8) + ghostExpr(check((bitIndexAfterAppending == bitIndexAfterHeader + nCurBlockSize1 * 8))) + + assert(bitIndexAfterAppending - bitIndexAfterHeader == nCurBlockSize1 * 8) + + val newRemaingItems = nRemainingItemsVar1 - nCurBlockSize1 + @ghost val newWrittenBlocks = currentlyWrittenBlocksOf0x4000 + nNewBlocksOf0x4000 + val newOffset = nCurOffset1 + nCurBlockSize1 + + val validatedOffset2: Int = newRemaingItems + (newRemaingItems / 0x4000) + 2 + assert(validatedOffset1 >= 0) + assert(validatedOffset2 >= 0) + + assert(validatedOffset1 - validatedOffset2 == nRemainingItemsVar1 + (nRemainingItemsVar1 / 0x4000) - 1 + 2 - (nRemainingItemsVar1 - nCurBlockSize1) - (nRemainingItemsVar1 - nCurBlockSize1) / 0x4000 - 2) + assert(validatedOffset1 - validatedOffset2 == nCurBlockSize1 - 1 + nCurBlockSize1 / 0x4000) + assert(validatedOffset1 - validatedOffset2 >= 0) + + assert(BitStream.invariant(currentBitAfterHeader, currentByteAfterHeader, bufferLength)) + assert(BitStream.invariant(currentBitAfterAppending, currentByteAfterAppending, bufferLength)) + assert(validatedOffset1 >= 0) + assert(validatedOffset2 >= 0) + assert(bitIndexAfterHeader <= bitIndexAfterAppending) + assert(validatedOffset2 <= validatedOffset1) + assert(8*validatedOffset2 <= 8*validatedOffset1) + assert(BitStream.bitIndex(bufferLength, currentByteAfterHeader, currentBitAfterHeader) == bitIndexAfterHeader) + assert(BitStream.bitIndex(bufferLength, currentByteAfterAppending, currentBitAfterAppending) == bitIndexAfterAppending) + assert(bitIndexAfterAppending - bitIndexAfterHeader <= 8*validatedOffset1 - 8*validatedOffset2) + + assert(BitStream.validate_offset_bytes(bufferLength, currentByteAfterHeader, currentBitAfterHeader, validatedOffset1)) // should pass + + assert(BitStream.validate_offset_bits(bufferLength, currentByteAfterHeader, currentBitAfterHeader, 8*validatedOffset1)) + + + ghostExpr(lemmaAdvanceBitIndexLessMaintainOffset(bufferLength, currentByteAfterHeader, currentBitAfterHeader, bitIndexAfterHeader, currentByteAfterAppending, currentBitAfterAppending, bitIndexAfterAppending, 8*validatedOffset1, 8*validatedOffset2)) + + assert((BitStream.validate_offset_bits(bufferLength, bitStream.currentByte, bitStream.currentBit, 8*validatedOffset2))) + ghostExpr(lemmaValidateOffsetBitsBytesEquiv(bufferLength, bitStream.currentByte, bitStream.currentBit, 8*validatedOffset2, validatedOffset2)) + assert((BitStream.validate_offset_bytes(bufferLength, bitStream.currentByte, bitStream.currentBit, validatedOffset2))) + + val res = encodeOctetString_fragmentation_innerWhile(arr, nCount, newWrittenBlocks , newRemaingItems, newOffset , BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) + val resNRemaining = res._1 + val resOffset = res._2 + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, res._1 + 2)) + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, res._1 + 2))) + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, resNRemaining + 2))) + @ghost val bitIndexAfterRecursive = BitStream.bitIndex(bufferLength, bitStream.currentByte, bitStream.currentBit ) + + assert(resNRemaining + resOffset == nCount) + assert(resNRemaining <= 0x4000) + assert(bitIndexAfterRecursive <= bitIndexAfterAppending + (newRemaingItems / 0x4000) * 8 + newRemaingItems * 8 - resNRemaining*8) + assert(newRemaingItems <= nRemainingItemsVar1) + assert(newRemaingItems == nRemainingItemsVar1 - nCurBlockSize1) + assert(bitIndexAfterAppending == bitIndexAfterHeader + nCurBlockSize1 * 8 ) + assert(bitIndexBeforeHeader == bitIndex) + assert(bitIndexAfterHeader <= bitIndexBeforeHeader + 4 * NO_OF_BITS_IN_BYTE) + // assert(bitIndexAfterHeader + (nCurBlockSize1 / 0x4000) * 8 - resNRemaining * 8 <= bitIndex - resNRemaining*8 ) + // assert(bitIndexAfterHeader + (nCurBlockSize1 / 0x4000) * 8 + ( nRemainingItemsVar1 ) * 8 - resNRemaining* 8 <= bitIndex + nRemainingItemsVar1 * 8 - resNRemaining*8 ) + // assert(bitIndexAfterHeader + nCurBlockSize1 * 8 + (( nRemainingItemsVar1 - nCurBlockSize1) / 0x4000) * 8 + ( nRemainingItemsVar1 - nCurBlockSize1) * 8 - resNRemaining * 8 <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - resNRemaining*8 ) + assert(bitIndexAfterAppending + (newRemaingItems / 0x4000) * 8 + newRemaingItems * 8 - resNRemaining*8 <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - resNRemaining*8 ) + assert(bitIndexAfterRecursive <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - resNRemaining*8) + + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, resNRemaining + 2))) + ghostExpr(check( BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) <= bitIndexAfterRecursive)) + ghostExpr(check( BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - resNRemaining*8)) + ghostExpr(check(resNRemaining + resOffset == nCount )) + ghostExpr(check(resNRemaining >= 0 )) + ghostExpr(check(resOffset >= 0 )) + ghostExpr(check(resNRemaining <= 0x4000 )) + + (resNRemaining, resOffset) + else + ghostExpr(check(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 2))) + ghostExpr(check( BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - nRemainingItemsVar1 * 8 )) + ghostExpr(check(nRemainingItemsVar1 + nCurOffset1 == nCount )) + ghostExpr(check(nRemainingItemsVar1 >= 0 )) + ghostExpr(check(nCurOffset1 >= 0 )) + ghostExpr(check(nRemainingItemsVar1 <= 0x4000 )) + (nRemainingItemsVar1, nCurOffset1) + } ensuring(res => + BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 * 8 - res._1 * 8 && + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, res._1 + 2) && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + res._1 + res._2 == nCount && + res._1 >= 0 && + res._2 >= 0 && + res._1 <= 0x4000 && + old(this).bitStream.buf.length == bitStream.buf.length + ) + /** + * Append the bytes in the given array to the BitStream, starting at from index, to the to index (exclusive) + * + * @param bitStream + * @param arr + * @param from + * @param to + */ + def encodeOctetString_fragmentation_innerMostWhile(arr: Array[UByte], from: Int, to: Int, bitIndex: Long): Unit = { + require(from >= 0) + require(to >= 0) + require(from < to) + require(to <= arr.length) + require(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,to - from)) + require(BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) == bitIndex) + require((to - from) < Int.MaxValue / NO_OF_BITS_IN_BYTE) // to avoid overflow + require(bitIndex < Long.MaxValue - (to - from) * NO_OF_BITS_IN_BYTE) // to avoid overflow + decreases(to - from) + + @ghost val bitIndexBeforeAppending = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) + + @ghost val bufLength = bitStream.buf.length + + bitStream.appendByte(arr(from)) + + assert(bitStream.buf.length == bufLength) + + @ghost val bitIndexBeforeRecursive = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) + assert(bitIndexBeforeRecursive == bitIndexBeforeAppending + NO_OF_BITS_IN_BYTE) + + if from + 1 < to then + encodeOctetString_fragmentation_innerMostWhile(arr, from + 1, to, bitIndex + NO_OF_BITS_IN_BYTE) + + assert(bitStream.buf.length == bufLength) + @ghost val bitIndexAfterRecursive = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) + assert(bitIndexAfterRecursive == bitIndexBeforeRecursive + (to - from - 1) * NO_OF_BITS_IN_BYTE) + assert(NO_OF_BITS_IN_BYTE + (to - from - 1) * NO_OF_BITS_IN_BYTE == (to - from) * NO_OF_BITS_IN_BYTE) + assert(bitIndexAfterRecursive == bitIndexBeforeAppending + NO_OF_BITS_IN_BYTE + (to - from - 1) * NO_OF_BITS_IN_BYTE) + } ensuring(_ => + val oldBitStream = old(this).bitStream + BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) == bitIndex + (to - from) * NO_OF_BITS_IN_BYTE && + oldBitStream.buf.length == bitStream.buf.length + ) + + + @ghost + @opaque + @inlineOnce + def lemmaGetBitCountUnsignedFFEqualsEight(): Unit = { + + } ensuring(_ => GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + + @ghost + @opaque + @inlineOnce + def lemmaGetBitCountUnsigned7FFFEquals15(): Unit = { + + } ensuring(_ => GetBitCountUnsigned(stainless.math.wrapping(0x7FFF).toRawULong) == 15) + + @ghost + @opaque + @inlineOnce + def lemmaValidateOffsetBitsBytesEquiv(bufLength: Int, currentByte: Int, currentBit: Int, offsetBits: Int, offsetBytes: Int): Unit = { + require(BitStream.invariant(currentBit, currentByte, bufLength)) + require(offsetBits >= 0) + require(offsetBytes >= 0) + require(offsetBytes < Int.MaxValue / 8) + require(offsetBits == offsetBytes * 8) + require(BitStream.validate_offset_bits(bufLength, currentByte, currentBit, offsetBits)) + + } ensuring(_ => BitStream.validate_offset_bytes(bufLength, currentByte, currentBit, offsetBytes)) + /** + * Takes more than 100sec to verify, that's why it is extracted to a lemma, even though it does not need a specific proof + * + * @param bufLength + * @param currentByte1 + * @param currentBit1 + * @param bitIndex1 + * @param currentByte2 + * @param currentBit2 + * @param bitIndex2 + * @param offset1 + * @param offset2 + */ + @ghost + @opaque + @inlineOnce + def lemmaAdvanceBitIndexLessMaintainOffset( + bufLength: Int, + currentByte1: Int, currentBit1: Int, bitIndex1: Long, + currentByte2: Int, currentBit2: Int, bitIndex2: Long, + offset1Bits: Int, + offset2Bits: Int): Unit = { + require(BitStream.invariant(currentBit1, currentByte1, bufLength)) + require(BitStream.invariant(currentBit2, currentByte2, bufLength)) + require(offset1Bits >= 0) + require(offset2Bits >= 0) + require(bitIndex1 <= bitIndex2) + require(offset2Bits <= offset1Bits) + require(BitStream.bitIndex(bufLength, currentByte1, currentBit1) == bitIndex1) + require(BitStream.bitIndex(bufLength, currentByte2, currentBit2) == bitIndex2) + require(bitIndex2 - bitIndex1 <= offset1Bits - offset2Bits) + require(BitStream.validate_offset_bits(bufLength, currentByte1, currentBit1, offset1Bits)) + + } ensuring(_ => BitStream.validate_offset_bits(bufLength, currentByte2, currentBit2, offset2Bits)) + + + /** + * Undefined behaviour if the bitstream is invalid (i.e., not supported format or wrong) + * + * @param asn1SizeMax + */ def decodeOctetString_fragmentation(asn1SizeMax: Long): Array[UByte] = { require(asn1SizeMax >= 0 && asn1SizeMax < Int.MaxValue) + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + val arr: Array[UByte] = Array.fill(asn1SizeMax.toInt)(0.toRawUByte) var nCount: Int = 0 - var nLengthTmp1: Long = 0 - var nCurBlockSize1: Long = 0 - var nCurOffset1: Long = 0 + assert(arr.length == asn1SizeMax.toInt) - // get header data - var nRemainingItemsVar1: Long = decodeConstrainedWholeNumber(0, 0xFF) + var nLengthTmp1: Long = 0 + // var nCurBlockSize1: Long = 0 + // var nCurOffset1: Long = 0 // 11xx_xxxx header, there is a next fragment - (while (nRemainingItemsVar1 & 0xC0) == 0xC0 do - decreases(asn1SizeMax - nCurOffset1) // TODO: check experimental decrease - - // get current block size - if nRemainingItemsVar1 == 0xC4 then - nCurBlockSize1 = 0x10000 - else if nRemainingItemsVar1 == 0xC3 then - nCurBlockSize1 = 0xC000 - else if nRemainingItemsVar1 == 0xC2 then - nCurBlockSize1 = 0x8000 - else if nRemainingItemsVar1 == 0xC1 then - nCurBlockSize1 = 0x4000 - else - assert(false, "unsupported format") - - // fill current payload fragment into dest - var i1: Int = nCurOffset1.toInt - (while (nCurOffset1 + nCurBlockSize1 <= asn1SizeMax) && (i1 < (nCurOffset1 + nCurBlockSize1).toInt) do - decreases((nCurOffset1 + nCurBlockSize1).toInt - i1) - arr(i1) = readByte() - i1 += 1 - ).invariant(true) // TODO invariant - - // sum combined length - nLengthTmp1 += nCurBlockSize1 - // set offset for next run - nCurOffset1 += nCurBlockSize1 - - // get next header - nRemainingItemsVar1 = decodeConstrainedWholeNumber(0, 0xFF) - - ).invariant(true) // TODO invariant - + val resInnerWhile: (Long, Long) = decodeOctetString_fragmentation_innerWhile(arr, asn1SizeMax, 0) + var nRemainingItemsVar1 = resInnerWhile._1 + var nCurOffset1 = resInnerWhile._2 + nLengthTmp1 = nCurOffset1 // In the loops containing code, the nLengthTmp1 is updated along with the current offset, so has the same value after the loop + if(nRemainingItemsVar1 == -1L || nCurOffset1 == -1L) then + return arr + + // SAM given the code above in the encode function, this header is written when the number of remaining + // elements in <= 0x7F which is 127, and not 255 // 1000_0000 header, last fragment has size bigger than 255 - current byte is upper, need to get lower if (nRemainingItemsVar1 & 0x80) > 0 then nRemainingItemsVar1 <<= 8 // put upper at correct position + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + // SAM Guard if + if(!BitStream.validate_offset_byte(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) then + return arr + + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + assert(BitStream.validate_offset_byte(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8)) + // get size (lower byte) nRemainingItemsVar1 |= decodeConstrainedWholeNumber(0, 0xFF) // combine 15bit (7 upper, 8 lower) into size nRemainingItemsVar1 &= 0x7FFF // clear the control bit + // SAM Guard if + if(nRemainingItemsVar1 < 0 || nRemainingItemsVar1 > asn1SizeMax || nCurOffset1 > asn1SizeMax - nRemainingItemsVar1 ) then + return arr + assert(nCurOffset1 + nRemainingItemsVar1 <= asn1SizeMax) // TODO check with C implementation and standard var i1: Int = nCurOffset1.toInt + + // This loop is implemented with the same helper function as the inner most loop // fill last payload fragment into dest - (while i1 < (nCurOffset1 + nRemainingItemsVar1).toInt do - decreases((nCurOffset1 + nRemainingItemsVar1).toInt - i1) - arr(i1) = readByte() - i1 += 1 - ).invariant(true) // TODO invariant + // (while i1 < (nCurOffset1 + nRemainingItemsVar1).toInt do + // decreases((nCurOffset1 + nRemainingItemsVar1).toInt - i1) + // arr(i1) = readByte() + // i1 += 1 + // ).invariant(true) // TODO invariant + + assert(arr.length == asn1SizeMax.toInt) + + decodeOctetString_fragmentation_innerMostWhile(arr, asn1SizeMax, nCurOffset1.toInt, (nCurOffset1 + nRemainingItemsVar1).toInt) // add remainingSize to already written size - this var holds the absolut number in all fragments - nLengthTmp1 += nRemainingItemsVar1 + nLengthTmp1 += nRemainingItemsVar1 // which is equal to curOffset + nRemainingItemsVar1 - // resize output array and copy data - assert((nLengthTmp1 >= 1) && (nLengthTmp1 <= asn1SizeMax)) // TODO check with C implementation and standard + + // // resize output array and copy data + assert((nLengthTmp1 >= 0) && (nLengthTmp1 <= asn1SizeMax)) + // assert((nLengthTmp1 >= 1) && (nLengthTmp1 <= asn1SizeMax)) // TODO check with C implementation and standard + // SAM according to the C implementation, if the nLengthTmp1 == 0, it should fail, so + if(nLengthTmp1 == 0) then + return Array.empty val newArr: Array[UByte] = Array.fill(nLengthTmp1.toInt)(0.toRawUByte) arrayCopyOffsetLen(arr, newArr, 0, 0, newArr.length) newArr - } + } ensuring(_ => BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + + + /** + * Decodes the fragments until it encounters a header s.t., nRemainingItemsVar1 & 0xC0) != 0xC0 + * Undefined behaviour if the bitstream is invalid (i.e., not supported format or wrong) + * Returns the remaining number of items and the current offset (or (-1, -1) in case of error) + * + * @param arr + * @param asn1SizeMax + * @param nRemainingItemsVar1 + * @param nCurOffset1 + */ + def decodeOctetString_fragmentation_innerWhile(arr: Array[UByte], asn1SizeMax: Long, nCurOffset1: Long): (Long, Long) = { + require(asn1SizeMax >= 0 && asn1SizeMax < Int.MaxValue) + require(arr.length == asn1SizeMax) + require(nCurOffset1 >= 0) + require(nCurOffset1 <= asn1SizeMax) + staticRequire(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + decreases(asn1SizeMax - nCurOffset1) + + // Implements the following loop + // (while (nRemainingItemsVar1 & 0xC0) == 0xC0 do + // decreases(asn1SizeMax - nCurOffset1) // TODO: check experimental decrease + + // // get current block size + // if nRemainingItemsVar1 == 0xC4 then + // nCurBlockSize1 = 0x10000 + // else if nRemainingItemsVar1 == 0xC3 then + // nCurBlockSize1 = 0xC000 + // else if nRemainingItemsVar1 == 0xC2 then + // nCurBlockSize1 = 0x8000 + // else if nRemainingItemsVar1 == 0xC1 then + // nCurBlockSize1 = 0x4000 + // else + // return arr + // assert(false, "unsupported format") + + // // fill current payload fragment into dest + // decodeOctetString_fragmentation_innerMostWhile(arr, asn1SizeMax, nCurOffset1, nCurOffset1 + nCurBlockSize1) + + // // sum combined length + // nLengthTmp1 += nCurBlockSize1 + // // set offset for next run + // nCurOffset1 += nCurBlockSize1 + + // // get next header + // nRemainingItemsVar1 = decodeConstrainedWholeNumber(0, 0xFF) + + // ).invariant(true) // TODO invariant + + if(!BitStream.validate_offset_byte(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) then + return (-1, -1L) + + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + + assert(GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + assert(BitStream.validate_offset_byte(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8)) + val nRemainingItemsVar1: Long = decodeConstrainedWholeNumber(0, 0xFF) + + + // get current block size + val nCurBlockSize1: Long = if nRemainingItemsVar1 == 0xC4 then + 0x10000 + else if nRemainingItemsVar1 == 0xC3 then + 0xC000 + else if nRemainingItemsVar1 == 0xC2 then + 0x8000 + else if nRemainingItemsVar1 == 0xC1 then + 0x4000 + else if (nRemainingItemsVar1 & 0xC0) != 0xC0 then + // End of the recursion, out with valid values + 1L + else + // unsupported format + -1L + // assert(false, "unsupported format") + + if nCurBlockSize1 == -1L then + return (-1, -1L) + + if nCurBlockSize1 == 1L then + return (nRemainingItemsVar1, nCurOffset1) + + if(nCurOffset1 > (asn1SizeMax.toLong - nCurBlockSize1)) then + return (-1, -1L) + + assert(arr.length == asn1SizeMax.toInt) + decodeOctetString_fragmentation_innerMostWhile(arr, asn1SizeMax, nCurOffset1.toInt, nCurOffset1.toInt + nCurBlockSize1.toInt) + + // sum combined length + // nLengthTmp1 += nCurBlockSize1 + // val newNLengthTmp1 = nLengthTmp1 + nCurBlockSize1 + // set offset for next run + // nCurOffset1 += nCurBlockSize1 + val newNCurOffset1 = nCurOffset1 + nCurBlockSize1 + + // get next header + // nRemainingItemsVar1 = decodeConstrainedWholeNumber(0, 0xFF) + + assert(arr.length == asn1SizeMax.toInt) + decodeOctetString_fragmentation_innerWhile(arr, asn1SizeMax, newNCurOffset1) + + } ensuring(res => + (res._2 >= 0 && res._2 <= asn1SizeMax || res == (-1L, -1L)) && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + old(this).bitStream.buf.length == bitStream.buf.length && + arr.length == asn1SizeMax.toInt && + old(arr).length == arr.length + ) + + /** + * Read bytes from bitstream, and write them in the array, starting at from and to to index. + * If the bitstream is invalid, abort. + * + * @param arr + * @param asn1SizeMax + * @param from + * @param to + * @return + */ + def decodeOctetString_fragmentation_innerMostWhile(arr: Array[UByte], asn1SizeMax: Long, from: Int, to: Int): Unit = { + require(asn1SizeMax >= 0 && asn1SizeMax < Int.MaxValue) + require(from >= 0) + require(to >= 0) + require(to >= from) + require(arr.length == asn1SizeMax.toInt) + staticRequire(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + decreases(to - from) + + // Implements the following loop + // var i1: Int = nCurOffset1.toInt + // (while (nCurOffset1 + nCurBlockSize1 <= asn1SizeMax) && (i1 < (nCurOffset1 + nCurBlockSize1).toInt) do + // decreases((nCurOffset1 + nCurBlockSize1).toInt - i1) + // arr(i1) = readByte() + // i1 += 1 + // ).invariant(true) // TODO invariant + + if(from >= to) then + return + // SAM guard ifs + if(from >= asn1SizeMax) then + return + if(!BitStream.validate_offset_byte(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) then + return + val nextByte = readByte() + arr(from) = nextByte + decodeOctetString_fragmentation_innerMostWhile(arr, asn1SizeMax, from + 1, to) + () + + } ensuring(_ => + old(this).buf.length == bitStream.buf.length && + arr.length == asn1SizeMax.toInt && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + old(this).bitStream.buf.length == bitStream.buf.length && + old(arr).length == arr.length + ) def encodeOctetString(arr: Array[UByte], nCount: Int, asn1SizeMin: Long, asn1SizeMax: Long) = { + require(asn1SizeMin >= 0) + require(asn1SizeMax >= 0 && asn1SizeMax < Int.MaxValue) // to match the decodeOctetString_fragmentation spec + require(asn1SizeMin <= asn1SizeMax) + require(arr.length >= nCount) require(nCount >= asn1SizeMin && nCount <= asn1SizeMax) + require(nCount < Int.MaxValue - GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong)) + require( nCount < Int.MaxValue / 8 - 2 - (nCount / 0x4000) ) + require( + if(asn1SizeMax < 65536) then + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount + GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong)) + else + BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount + 8 * (nCount / 0x4000) + 2) + ) if asn1SizeMax < 65536 then if asn1SizeMin != asn1SizeMax then encodeConstrainedWholeNumber(nCount.toLong, asn1SizeMin, asn1SizeMax) + assert(BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount)) encodeOctetString_no_length(arr, nCount) else @@ -774,22 +1714,47 @@ case class Codec private [asn1scala](bitStream: BitStream) { } def decodeOctetString(asn1SizeMin: Long, asn1SizeMax: Long): Array[UByte] = { + require(asn1SizeMin >= 0) + require(asn1SizeMax >= 0 && asn1SizeMax < Int.MaxValue) + require(asn1SizeMin <= asn1SizeMax) if asn1SizeMax >= 0x1_00_00 then // 65'536, bigger than 2 unsigned bytes return decodeOctetString_fragmentation(asn1SizeMax) var nCount: Int = 0 if asn1SizeMin != asn1SizeMax then + // SAM guard if + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + if(!BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong))) then + return Array.empty nCount = decodeConstrainedWholeNumber(asn1SizeMin, asn1SizeMax).toInt else nCount = asn1SizeMin.toInt assert(nCount >= asn1SizeMin && nCount <= asn1SizeMax) // TODO check with C implementation and standard + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + if(!BitStream.validate_offset_bytes(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit,nCount)) then + return Array.empty decodeOctetString_no_length(nCount) } def encodeBitString(arr: Array[UByte], nCount: Int, asn1SizeMin: Long, asn1SizeMax: Long): Unit = { + require(asn1SizeMin >= 0) + require(asn1SizeMax >= 0) + require(asn1SizeMin <= asn1SizeMax) + require(arr.length >= nCount) + require(nCount <= asn1SizeMax) + require(nCount >= 0) + require(asn1SizeMax < Int.MaxValue) + require(asn1SizeMax < Int.MaxValue - 8*(asn1SizeMax / 0x4000) - 16) + require(nCount >= asn1SizeMin) // TODO SAM check + require(arr.length >= 0) + require( + if(asn1SizeMax < 65536 && asn1SizeMin != asn1SizeMax) then BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong) + nCount) + else if(asn1SizeMax < 65536) then BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount ) + else BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount + 8 * (nCount / 0x4000) + 16 ) + ) if asn1SizeMax < 65536 then if asn1SizeMin != asn1SizeMax then encodeConstrainedWholeNumber(nCount.toLong, asn1SizeMin, asn1SizeMax) @@ -800,240 +1765,290 @@ case class Codec private [asn1scala](bitStream: BitStream) { var nRemainingItemsVar1: Long = nCount.toLong var nCurBlockSize1: Long = 0 var nCurOffset1: Long = 0 - (while nRemainingItemsVar1 >= 0x4000 do - decreases(nRemainingItemsVar1) - - if nRemainingItemsVar1 >= 0x10000 then - nCurBlockSize1 = 0x10000 - encodeConstrainedWholeNumber(0xC4, 0, 0xFF) - - else if nRemainingItemsVar1 >= 0xC000 then - nCurBlockSize1 = 0xC000 - encodeConstrainedWholeNumber(0xC3, 0, 0xFF) - else if nRemainingItemsVar1 >= 0x8000 then - nCurBlockSize1 = 0x8000 - encodeConstrainedWholeNumber(0xC2, 0, 0xFF) - else - nCurBlockSize1 = 0x4000 - encodeConstrainedWholeNumber(0xC1, 0, 0xFF) - - val t: Array[UByte] = Array.fill(nCurBlockSize1.toInt)(0.toRawUByte) // STAINLESS: arr.slice((nCurOffset1 / 8).toInt, (nCurOffset1 / 8).toInt + nCurBlockSize1.toInt) - appendBitsMSBFirst(t, nCurBlockSize1.toInt) - nCurOffset1 += nCurBlockSize1 - nRemainingItemsVar1 -= nCurBlockSize1 - ).invariant(true) // TODO invariant + val res = encodeBitString_while(arr, nCount, asn1SizeMin, asn1SizeMax, nRemainingItemsVar1, nCurOffset1, BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) + nRemainingItemsVar1 = res._1 + nCurOffset1 = res._2 + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 16)) if nRemainingItemsVar1 <= 0x7F then + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8)) encodeConstrainedWholeNumber(nRemainingItemsVar1, 0, 0xFF) else + ghostExpr(lemmaGetBitCountUnsigned7FFFEquals15()) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 16)) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 1)) appendBit(true) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 15)) encodeConstrainedWholeNumber(nRemainingItemsVar1, 0, 0x7FFF) - val t: Array[UByte] = Array.fill(nRemainingItemsVar1.toInt)(0.toRawUByte) // STAINLESS: arr.slice((nCurOffset1 / 8).toInt, (nCurOffset1 / 8).toInt + nRemainingItemsVar1.toInt) - appendBitsMSBFirst(t, nRemainingItemsVar1.toInt) - } + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1)) - def decodeBitString(asn1SizeMin: Long, asn1SizeMax: Long): Array[UByte] = { - require(asn1SizeMax <= Int.MaxValue) - // TODO enhance precondition + // val t: Array[UByte] = Array.fill(nRemainingItemsVar1.toInt)(0.toRawUByte) // STAINLESS: arr.slice((nCurOffset1 / 8).toInt, (nCurOffset1 / 8).toInt + nRemainingItemsVar1.toInt) + appendBitsMSBFirst(arr, nRemainingItemsVar1.toInt, nCurOffset1.toInt) + } - if (asn1SizeMax < 65536) { - var nCount: Long = 0 - if asn1SizeMin != asn1SizeMax then - nCount = decodeConstrainedWholeNumber(asn1SizeMin, asn1SizeMax) + def encodeBitString_while(arr: Array[UByte], nCount: Int, asn1SizeMin: Long, asn1SizeMax: Long, nRemainingItemsVar1: Long, nCurOffset1: Long, bitIndex: Long): (Long, Long) = { + require(asn1SizeMin >= 0) + require(asn1SizeMax >= 0) + require(asn1SizeMin <= asn1SizeMax) + require(nCount <= asn1SizeMax) + require(nCount >= 0) + require(nCount >= asn1SizeMin) // TODO SAM check + require(nCount <= arr.length) + require(asn1SizeMax < Int.MaxValue) + require(nRemainingItemsVar1 >= 0) + require(nCurOffset1 >= 0) + require(nRemainingItemsVar1 == nCount - nCurOffset1) + require(bitIndex == BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit)) + require(nCount < Int.MaxValue - 8*(nCount / 0x4000) - 16) + staticRequire(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + require(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 8*(nRemainingItemsVar1 / 0x4000) + 16)) + + + decreases(nCount - nCurOffset1) + + assert(nCount == nRemainingItemsVar1 + nCurOffset1) + if(nRemainingItemsVar1 < 0x4000) then + (nRemainingItemsVar1, nCurOffset1) + else + val nCurBlockSize1: Int = if nRemainingItemsVar1 >= 0x10000 then + 0x10000 + else if nRemainingItemsVar1 >= 0xC000 then + 0xC000 + else if nRemainingItemsVar1 >= 0x8000 then + 0x8000 else - nCount = asn1SizeMin + 0x4000 - return readBits(nCount.toInt) - - } + @ghost val bitIndexBeforeHeader = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) + @ghost val currentByteBeforeHeader = bitStream.currentByte + @ghost val currentBitBeforeHeader = bitStream.currentBit + @ghost val bufferLength = bitStream.buf.length - var nCurBlockSize1: Long = 0 - var nCurOffset1: Long = 0 - var nLengthTmp1: Long = 0 - var nRemainingItemsVar1: Long = decodeConstrainedWholeNumber(0, 0xFF) - val arr: Array[UByte] = Array.fill(asn1SizeMax.toInt)(0.toRawUByte) - (while (nRemainingItemsVar1 & 0xC0) == 0xC0 do - decreases(asn1SizeMax - nCurOffset1) // TODO: check experimental decrease - if nRemainingItemsVar1 == 0xC4 then - nCurBlockSize1 = 0x10000 - else if nRemainingItemsVar1 == 0xC3 then - nCurBlockSize1 = 0xC000 - else if nRemainingItemsVar1 == 0xC2 then - nCurBlockSize1 = 0x8000 - else if nRemainingItemsVar1 == 0xC1 then - nCurBlockSize1 = 0x4000 + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8)) + if nCurBlockSize1 == 0x10000 then + encodeConstrainedWholeNumber(0xC4, 0, 0xFF) + else if nCurBlockSize1 == 0xC000 then + encodeConstrainedWholeNumber(0xC3, 0, 0xFF) + else if nCurBlockSize1 == 0x8000 then + encodeConstrainedWholeNumber(0xC2, 0, 0xFF) else - assert(false, "broken State") // TODO check with C implementation and standard + encodeConstrainedWholeNumber(0xC1, 0, 0xFF) - assert(nCurOffset1 + nCurBlockSize1 > asn1SizeMax) + assert(bitStream.buf.length == bufferLength) - arrayCopyOffsetLen(readBits(nCurBlockSize1.toInt), arr, 0, (nCurOffset1 / 8).toInt, nCurBlockSize1.toInt) - nLengthTmp1 += nCurBlockSize1 - nCurOffset1 += nCurBlockSize1 - nRemainingItemsVar1 = decodeConstrainedWholeNumber(0, 0xFF) + @ghost val bitIndexAfterHeader = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) + @ghost val currentByteAfterHeader = bitStream.currentByte + @ghost val currentBitAfterHeader = bitStream.currentBit - ).invariant(true) // TODO invariant + assert(bitIndexAfterHeader == bitIndexBeforeHeader + 8) - if (nRemainingItemsVar1 & 0x80) > 0 then - nRemainingItemsVar1 <<= 8 - nRemainingItemsVar1 |= decodeConstrainedWholeNumber(0, 0xFF) - nRemainingItemsVar1 &= 0x7FFF + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 8*(nRemainingItemsVar1 / 0x4000) + 16 - 8)) - assert(nCurOffset1 + nRemainingItemsVar1 <= asn1SizeMax) - - arrayCopyOffsetLen(readBits(nRemainingItemsVar1.toInt), arr, 0, (nCurOffset1 / 8).toInt, nRemainingItemsVar1.toInt) - nLengthTmp1 += nRemainingItemsVar1 - assert((nLengthTmp1 >= 1) && (nLengthTmp1 <= asn1SizeMax)) - - arr - } + // val t: Array[UByte] = Array.fill(nCurBlockSize1.toInt)(0.toRawUByte) // STAINLESS: arr.slice((nCurOffset1 / 8).toInt, (nCurOffset1 / 8).toInt + nCurBlockSize1.toInt) + appendBitsMSBFirst(arr, nCurBlockSize1.toInt, nCurOffset1.toInt) + val newOffset = nCurOffset1 + nCurBlockSize1 + val newRemaingItems = nRemainingItemsVar1 - nCurBlockSize1 - // ***** Public wrapper for bitstream functions - - def appendBitOne(): Unit = { - require(bitStream.validate_offset_bit()) - bitStream.appendBitOne() - } + @ghost val currentBitAfterAppending = bitStream.currentBit + @ghost val currentByteAfterAppending = bitStream.currentByte + val newBitIndex = BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit) - def appendBitZero(): Unit = { - require(bitStream.validate_offset_bit()) - bitStream.appendBitZero() - } + assert(newBitIndex == bitIndexAfterHeader + nCurBlockSize1) + assert(newRemaingItems == nRemainingItemsVar1 - nCurBlockSize1) + assert(newOffset == nCurOffset1 + nCurBlockSize1) - def appendBit(v: Boolean): Unit = { - require(bitStream.validate_offset_bit()) - bitStream.appendBit(v) - } + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1 + 8*(nRemainingItemsVar1 / 0x4000) + 16 - nCurBlockSize1 - 8)) // REALLY SLOW : > 160sec + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, newRemaingItems + 8*(newRemaingItems / 0x4000) + 16)) - def peekBit(): Boolean = { - require(bitStream.validate_offset_bit()) - bitStream.peekBit() - } + encodeBitString_while(arr, nCount, asn1SizeMin, asn1SizeMax, newRemaingItems, newOffset, newBitIndex) + } ensuring (res => + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + // BitStream.bitIndex(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit ) <= bitIndex + (nRemainingItemsVar1 / 0x4000) * 8 + nRemainingItemsVar1 - res._1 && + BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, res._1 + 16) && + res._1 + res._2 == nCount && + res._1 >= 0 && + res._2 >= 0 && + res._1 <= 0x4000 && + old(this).bitStream.buf.length == bitStream.buf.length + ) - def readBit(): Boolean = { - require(bitStream.validate_offset_bit()) - bitStream.readBit() - } + def decodeBitString(asn1SizeMin: Long, asn1SizeMax: Long): Array[UByte] = { + require(asn1SizeMax >= 0) + require(asn1SizeMax <= Int.MaxValue) + require(asn1SizeMin >= 0) + require(asn1SizeMin <= asn1SizeMax) - def appendNZeroBits(nBits: Long): Unit = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendNZeroBits(nBits) - } + if (asn1SizeMax < 65536) { + var nCount: Long = 0 + if asn1SizeMin != asn1SizeMax then + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong)) then + return Array.empty - def appendNOneBits(nBits: Long): Unit = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendNOneBits(nBits) - } + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(asn1SizeMax - asn1SizeMin).toRawULong))) + nCount = decodeConstrainedWholeNumber(asn1SizeMin, asn1SizeMax) + else + nCount = asn1SizeMin - def appendBitsLSBFirst(v: Long, nBits: Int): Unit = { // TODO remove if never used - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendBitsLSBFirst(v, nBits) - } + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount.toInt) then + return Array.empty - def appendBitsMSBFirst(srcBuffer: Array[UByte], nBits: Long): Unit = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendBitsMSBFirst(srcBuffer, nBits) - } + assert(BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCount.toInt)) + return readBits(nCount.toInt) - def appendNLeastSignificantBits(v: Long, nBits: Int): Unit = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendNLeastSignificantBits(v, nBits) - } + } - def readNLeastSignificantBits(nBits: Int): Long = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.readNLeastSignificantBits(nBits) - } + val arr: Array[UByte] = Array.fill(asn1SizeMax.toInt)(0.toRawUByte) - def readBits(nBits: Long): Array[UByte] = { - require(nBits >= 0 && bitStream.validate_offset_bits(nBits)) - bitStream.readBits(nBits) - } + val whileRes = decodeBitString_while(asn1SizeMin, asn1SizeMax, 0, arr) + var nRemainingItemsVar1 = whileRes._1 + var nCurOffset1 = whileRes._2 + var nLengthTmp1: Long = nCurOffset1 - def appendByte(value: UByte): Unit = { - require(bitStream.validate_offset_byte()) - bitStream.appendByte(value) - } + if nRemainingItemsVar1 == -1L || nCurOffset1 == -1L then + return Array.empty + assert(nRemainingItemsVar1 >= 0 && nRemainingItemsVar1 <= 0xFF) + if (nRemainingItemsVar1 & 0x80) > 0 then + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8) then + return Array.empty + nRemainingItemsVar1 <<= 8 + nRemainingItemsVar1 |= decodeConstrainedWholeNumber(0, 0xFF) + nRemainingItemsVar1 &= 0x7FFF - def readByte(): UByte = { - require(bitStream.validate_offset_byte()) - bitStream.readByte() - } + assert(nRemainingItemsVar1 >= 0 && nRemainingItemsVar1 <= 0x7FFF) - def appendByteArray(arr: Array[UByte], noOfBytes: Int): Unit = { - require(bitStream.validate_offset_bytes(noOfBytes)) - bitStream.appendByteArray(arr, noOfBytes) - } + if nCurOffset1 + nRemainingItemsVar1 > asn1SizeMax then + return Array.empty - def readByteArray(nBytes: Int): Array[UByte] = { - require(nBytes >= 0 && nBytes <= Integer.MAX_VALUE / NO_OF_BITS_IN_BYTE) - require(bitStream.validate_offset_bytes(nBytes)) - bitStream.readByteArray(nBytes) - } + assert(nCurOffset1 + nRemainingItemsVar1 <= asn1SizeMax) - def appendPartialByte(vVal: UByte, nBits: Byte): Unit = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.appendPartialByte(vVal, nBits) - } + assert(BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length)) + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nRemainingItemsVar1.toInt) then + return Array.empty - def readPartialByte(nBits: Int): UByte = { - require(nBits >= 0 && nBits <= NO_OF_BITS_IN_BYTE) - require(bitStream.validate_offset_bits(nBits)) - bitStream.readPartialByte(nBits) - } - def checkBitPatternPresent(bit_terminated_pattern: Array[UByte], nBits: Long): Boolean = { - require(bitStream.validate_offset_bits(nBits)) - bitStream.checkBitPatternPresent(bit_terminated_pattern, nBits) - } - - // broken in C - do not translate -// def readBits_nullterminated(bit_terminated_pattern: Array[UByte], bit_terminated_pattern_size_in_bits: Long, nMaxReadBits: Long): OptionMut[(Array[UByte], Long)] = { -// val isValidPrecondition = bitStream.validate_offset_bits(nMaxReadBits) -// assert(isValidPrecondition) -// isValidPrecondition match -// case true => SomeMut(bitStream.readBitsUntilTerminator(bit_terminated_pattern, bit_terminated_pattern_size_in_bits, nMaxReadBits)) -// case false => NoneMut() -// } - - def alignToByte(): Unit = { - require(bitStream.validate_offset_bits( - NO_OF_BITS_IN_BYTE - (bitStream.bitIndex() % NO_OF_BITS_IN_BYTE))) - bitStream.alignToByte() - } + val readBitsArray = readBits(nRemainingItemsVar1.toInt) - def alignToShort(): Unit = { - // TODO: precondition - bitStream.alignToShort() -// alignToByte() -// currentByte = ((currentByte + (NO_OF_BYTES_IN_JVM_SHORT - 1)) / NO_OF_BYTES_IN_JVM_SHORT) * NO_OF_BYTES_IN_JVM_SHORT - } + assert(nRemainingItemsVar1.toInt >= 0) + assert(nRemainingItemsVar1.toInt <= asn1SizeMax.toInt) + assert(readBitsArray.length == ((nRemainingItemsVar1 + NO_OF_BITS_IN_BYTE - 1) / NO_OF_BITS_IN_BYTE).toInt) + arrayCopyOffsetLen(readBitsArray, arr, 0, (nCurOffset1 / 8).toInt, readBitsArray.length) - def alignToInt(): Unit = { - // TODO: precondition - bitStream.alignToInt() -// alignToByte() -// currentByte = ((currentByte + (NO_OF_BYTES_IN_JVM_INT - 1)) / NO_OF_BYTES_IN_JVM_INT) * NO_OF_BYTES_IN_JVM_INT - } + nLengthTmp1 += nRemainingItemsVar1 - def resetBitIndex(): Unit = { - bitStream.resetBitIndex() - } + // Same as in decodeOctetString, we can only prove >= 0, not >= 1; at least not without assuming things about the buffer + // assert((nLengthTmp1 >= 1) && (nLengthTmp1 <= asn1SizeMax)) + assert((nLengthTmp1 >= 0) && (nLengthTmp1 <= asn1SizeMax)) + // SAM same here, according to C implementation it should fail if nLengthTmp1 == 0 + if(nLengthTmp1 == 0) then + return Array.empty - def getBufferLength: Int = { - bitStream.getBufferLength + arr } - /** - * - * @return the number of used bytes in the underlying buffer - * if the currentBit is not 0, currentByte is added by 1 - * - */ - def getLength: Int = { - bitStream.getLength - } + def decodeBitString_while(asn1SizeMin: Long, asn1SizeMax: Long, nCurOffset1: Long, arr: Array[UByte]): (Long, Long) = { + require(asn1SizeMax >= 0) + require(asn1SizeMax <= Int.MaxValue) + require(asn1SizeMin >= 0) + require(asn1SizeMin <= asn1SizeMax) + require(arr.length == asn1SizeMax.toInt) + require(nCurOffset1 >= 0) + require(nCurOffset1 <= asn1SizeMax) + + decreases(asn1SizeMax - nCurOffset1) + + // Implements this loop + + // (while (nRemainingItemsVar1 & 0xC0) == 0xC0 do + // decreases(asn1SizeMax - nCurOffset1) // TODO: check experimental decrease + // if nRemainingItemsVar1 == 0xC4 then + // nCurBlockSize1 = 0x10000 + // else if nRemainingItemsVar1 == 0xC3 then + // nCurBlockSize1 = 0xC000 + // else if nRemainingItemsVar1 == 0xC2 then + // nCurBlockSize1 = 0x8000 + // else if nRemainingItemsVar1 == 0xC1 then + // nCurBlockSize1 = 0x4000 + // else + // assert(false, "broken State") // TODO check with C implementation and standard + + // assert(nCurOffset1 + nCurBlockSize1 > asn1SizeMax) + + // arrayCopyOffsetLen(readBits(nCurBlockSize1.toInt), arr, 0, (nCurOffset1 / 8).toInt, nCurBlockSize1.toInt) + // nLengthTmp1 += nCurBlockSize1 + // nCurOffset1 += nCurBlockSize1 + // nRemainingItemsVar1 = decodeConstrainedWholeNumber(0, 0xFF) + + // ) + + @ghost val arrLength = arr.length + ghostExpr(lemmaGetBitCountUnsignedFFEqualsEight()) + assert(GetBitCountUnsigned(stainless.math.wrapping(0xFF).toRawULong) == 8) + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, 8) then + return (-1L, -1L) + + val nRemainingItemsVar1: Long = decodeConstrainedWholeNumber(0, 0xFF) + + if (nRemainingItemsVar1 & 0xC0) != 0xC0 then + return (nRemainingItemsVar1, nCurOffset1) + + val nCurBlockSize1 = if nRemainingItemsVar1 == 0xC4 then + 0x10000 + else if nRemainingItemsVar1 == 0xC3 then + 0xC000 + else if nRemainingItemsVar1 == 0xC2 then + 0x8000 + else if nRemainingItemsVar1 == 0xC1 then + 0x4000 + else + 0x0 //ERROR + // assert(false, "broken State") // TODO check with C implementation and standard + if nCurBlockSize1 == 0 then + return (-1L, -1L) + + // assert(nCurOffset1 + nCurBlockSize1 > asn1SizeMax) // SAM Why? + + if !BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nCurBlockSize1.toInt) then + return (-1L, -1L) + + val readBitsArrayLength = ((nCurBlockSize1 + NO_OF_BITS_IN_BYTE - 1) / NO_OF_BITS_IN_BYTE).toInt + + if(arr.length < readBitsArrayLength ) then + // the output array is too small, probably the bitstream is malformed (i.e., to many block headers or too big block sizes) + return (-1L, -1L) + + if((nCurOffset1 / 8).toInt > arr.length - readBitsArrayLength) then + // the output array is also too small, probably the bitstream is malformed (i.e., to many block headers or too big block sizes) + return (-1L, -1L) + + assert(0 <= readBitsArrayLength && readBitsArrayLength <= arr.length) + assert(0 <= (nCurOffset1 / 8).toInt && (nCurOffset1 / 8).toInt <= arr.length - readBitsArrayLength) + arrayCopyOffsetLen(readBits(nCurBlockSize1.toInt), arr, 0, (nCurOffset1 / 8).toInt, readBitsArrayLength) + val newNCurOffset1 = nCurOffset1 + nCurBlockSize1 + + assert(arr.length == arrLength) + assert(arrLength == asn1SizeMax.toInt) + + if(newNCurOffset1 > asn1SizeMax) then + // the bitstream is malformed, as they are too many blocks + return (-1L, -1L) + decodeBitString_while(asn1SizeMin, asn1SizeMax, newNCurOffset1, arr) + + } ensuring (res => + res == (-1L, -1L) + || + res._1 >= 0 && res._1 <= 0xFF && + res._2 >= 0 && res._2 <= asn1SizeMax && + BitStream.invariant(bitStream.currentBit, bitStream.currentByte, bitStream.buf.length) && + old(this).bitStream.buf.length == bitStream.buf.length && + arr.length == asn1SizeMax.toInt && + old(arr).length == arr.length + ) } diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_ACN.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_ACN.scala index a2470b7b6..5e6152ea2 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_ACN.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_ACN.scala @@ -1,9 +1,10 @@ package asn1scala -import stainless.lang.StaticChecks._ import stainless.lang.{None => None, ghost => ghostExpr, Option => Option, _} import stainless.math.{wrapping => wrappingExpr, _} import stainless.annotation._ +import stainless.proof._ +import stainless.lang.StaticChecks._ val FAILED_READ_ERR_CODE = 5400 @@ -25,16 +26,18 @@ object ACN { (ACN(Codec(r1)), ACN(Codec(r2))) } + // For showing invertibility of encoding - not fully integrated yet + /* @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_16_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(16)) - require(acn1.bitIndex() + 16 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 16)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 16 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16 )) val acn2Reset = acn2.resetAt(acn1) @@ -42,24 +45,24 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_big_endian_16_pure() { - val end = (acn1.base.bitStream.bitIndex() / 8 + 2).toInt + val end = (BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) / 8 + 2).toInt arrayRangesEqImpliesEq(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.currentByte, end) arrayRangesEqImpliesEq(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.currentByte + 1, end) }.ensuring { _ => - acn1Res.bitIndex() == acn2Res.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } } @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_32_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(32)) - require(acn1.bitIndex() + 32 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 32)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 32 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32 )) val acn2Reset = acn2.resetAt(acn1) @@ -67,7 +70,7 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_big_endian_32_pure() { - arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.bitIndex() + 32, 0, acn1.base.bitStream.bitIndex() + 16) + arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16) dec_Int_PositiveInteger_ConstSize_big_endian_16_prefixLemma(acn1, acn2.resetAt(acn1).withMovedBitIndex(16)) val (acn1_2, hi1) = acn1.dec_Int_PositiveInteger_ConstSize_big_endian_16_pure() val (acn2_2, hi2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_big_endian_16_pure() @@ -79,20 +82,20 @@ object ACN { val (_, lo2) = acn2_2.dec_Int_PositiveInteger_ConstSize_big_endian_16_pure() assert(lo1 == lo2) }.ensuring { _ => - acn1Res.base.bitStream.bitIndex() == acn2Res.base.bitStream.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } } @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_64_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(64)) - require(acn1.bitIndex() + 64 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 64)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 64 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64 )) val acn2Reset = acn2.resetAt(acn1) @@ -100,7 +103,7 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_big_endian_64_pure() { - arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.bitIndex() + 64, 0, acn1.base.bitStream.bitIndex() + 32) + arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32) dec_Int_PositiveInteger_ConstSize_big_endian_32_prefixLemma(acn1, acn2.resetAt(acn1).withMovedBitIndex(32)) val (acn1_2, hi1) = acn1.dec_Int_PositiveInteger_ConstSize_big_endian_32_pure() val (acn2_2, hi2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_big_endian_32_pure() @@ -112,20 +115,20 @@ object ACN { val (_, lo2) = acn2_2.dec_Int_PositiveInteger_ConstSize_big_endian_32_pure() assert(lo1 == lo2) }.ensuring { _ => - acn1Res.base.bitStream.bitIndex() == acn2Res.base.bitStream.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } } @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_16_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(16)) - require(acn1.bitIndex() + 16 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 16)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 16 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16 )) val acn2Reset = acn2.resetAt(acn1) @@ -133,24 +136,24 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_little_endian_16_pure() { - val end = (acn1.base.bitStream.bitIndex() / 8 + 2).toInt + val end = (BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) / 8 + 2).toInt arrayRangesEqImpliesEq(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.currentByte, end) arrayRangesEqImpliesEq(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.currentByte + 1, end) }.ensuring { _ => - acn1Res.bitIndex() == acn2Res.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } } @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_32_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(32)) - require(acn1.bitIndex() + 32 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 32)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 32 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32 )) val acn2Reset = acn2.resetAt(acn1) @@ -158,7 +161,7 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_little_endian_32_pure() { - arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.bitIndex() + 32, 0, acn1.base.bitStream.bitIndex() + 16) + arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 16) dec_Int_PositiveInteger_ConstSize_little_endian_16_prefixLemma(acn1, acn2.resetAt(acn1).withMovedBitIndex(16)) val (acn1_2, hi1) = acn1.dec_Int_PositiveInteger_ConstSize_little_endian_16_pure() val (acn2_2, hi2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_little_endian_16_pure() @@ -170,20 +173,20 @@ object ACN { val (_, lo2) = acn2_2.dec_Int_PositiveInteger_ConstSize_little_endian_16_pure() assert(lo1 == lo2) }.ensuring { _ => - acn1Res.base.bitStream.bitIndex() == acn2Res.base.bitStream.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } } @ghost @pure @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_64_prefixLemma(acn1: ACN, acn2: ACN): Unit = { - require(acn1.bufLength() == acn2.bufLength()) - require(acn1.validate_offset_bits(64)) - require(acn1.bitIndex() + 64 <= acn2.bitIndex()) + require(acn1.base.bufLength() == acn2.base.bufLength()) + require(BitStream.validate_offset_bits(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit, 64)) + require(BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64 <= BitStream.bitIndex(acn2.base.bitStream.buf.length, acn2.base.bitStream.currentByte, acn2.base.bitStream.currentBit)) // TODO: Needed? require(arrayBitRangesEq( acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, - acn1.bitIndex() + 64 + BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64 )) val acn2Reset = acn2.resetAt(acn1) @@ -191,7 +194,7 @@ object ACN { val (acn2Res, i2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_little_endian_64_pure() { - arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, acn1.base.bitStream.bitIndex() + 64, 0, acn1.base.bitStream.bitIndex() + 32) + arrayBitRangesEqSlicedLemma(acn1.base.bitStream.buf, acn2.base.bitStream.buf, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 64, 0, BitStream.bitIndex(acn1.base.bitStream.buf.length, acn1.base.bitStream.currentByte, acn1.base.bitStream.currentBit) + 32) dec_Int_PositiveInteger_ConstSize_little_endian_32_prefixLemma(acn1, acn2.resetAt(acn1).withMovedBitIndex(32)) val (acn1_2, hi1) = acn1.dec_Int_PositiveInteger_ConstSize_little_endian_32_pure() val (acn2_2, hi2) = acn2Reset.dec_Int_PositiveInteger_ConstSize_little_endian_32_pure() @@ -203,37 +206,102 @@ object ACN { val (_, lo2) = acn2_2.dec_Int_PositiveInteger_ConstSize_little_endian_32_pure() assert(lo1 == lo2) }.ensuring { _ => - acn1Res.base.bitStream.bitIndex() == acn2Res.base.bitStream.bitIndex() && i1 == i2 + BitStream.bitIndex(acn1Res.base.bitStream.buf.length, acn1Res.base.bitStream.currentByte, acn1Res.base.bitStream.currentBit) == BitStream.bitIndex(acn2Res.base.bitStream.buf.length, acn2Res.base.bitStream.currentByte, acn2Res.base.bitStream.currentBit) && i1 == i2 } - } + }*/ } case class ACN(base: Codec) { import BitStream.* import ACN.* import base.* - export base.* // TODO: generates invalid VCs + // export base.{isPrefixOf => _, withMovedBitIndex => _, withMovedByteIndex => _, *} /*ACN Integer functions*/ - def enc_Int_PositiveInteger_ConstSize(intVal: Int, encodedSizeInBits: Int): Unit = + def enc_Int_PositiveInteger_ConstSize(intVal: Int, encodedSizeInBits: Int): Unit = { + val nBits: Int = GetBitCountUnsigned(intVal.toLong.toRawULong) + require(nBits <= encodedSizeInBits && encodedSizeInBits <= 64) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) enc_Int_PositiveInteger_ConstSize(intVal.toLong.toRawULong, encodedSizeInBits) + } + @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize(intVal: ULong, encodedSizeInBits: Int): Unit = { - if encodedSizeInBits == 0 then - return - + require(encodedSizeInBits >= 0 && encodedSizeInBits <= 64) /* Get number of bits*/ val nBits: Int = GetBitCountUnsigned(intVal) - /* put required zeros*/ - // TODO what if nBits > encodedSizeInBits ?? - appendNZeroBits(encodedSizeInBits - nBits) - /*Encode number */ - encodeUnsignedInteger(intVal) + require(nBits <= encodedSizeInBits && encodedSizeInBits <= 64) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) + + @ghost val this1 = snapshot(this) + if (encodedSizeInBits != 0) { + /* put required zeros*/ + val diff = encodedSizeInBits - nBits + appendNZeroBits(diff) + // @ghost val this2 = snapshot(this) + ghostExpr { + validateOffsetBitsDifferenceLemma(this1.base.bitStream, this.base.bitStream, encodedSizeInBits, diff) + } + /*Encode number */ + encodeUnsignedInteger(intVal) + /*ghostExpr { + assert(BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(this2.base.bitStream.buf.length, this2.base.bitStream.currentByte, this2.base.bitStream.currentBit) + nBits) + assert(BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(this1.base.bitStream.buf.length, this1.base.bitStream.currentByte, this1.base.bitStream.currentBit) + encodedSizeInBits) + validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) + val this2Reset = this2.resetAt(this1) + val (r1_1, r3_1) = ACN.reader(this1, this) + validateOffsetBitsContentIrrelevancyLemma(this1.base.bitStream, this.base.bitStream.buf, encodedSizeInBits) + val (r3Got, iGot) = r1_1.dec_Int_PositiveInteger_ConstSize_pure(encodedSizeInBits) + + check(this1.base.bufLength() == this.base.bufLength()) + check(BitStream.bitIndex(this.base.bitStream.buf.length, this.base.bitStream.currentByte, this.base.bitStream.currentBit) == BitStream.bitIndex(this1.base.bitStream.buf.length, this1.base.bitStream.currentByte, this1.base.bitStream.currentBit) + encodedSizeInBits ) + + if (encodedSizeInBits != nBits) { + checkBitsLoopPrefixLemma2(this2Reset.base.bitStream, this.base.bitStream, diff, false, 0) + + val (r2_2, r3_2) = ACN.reader(this2, this) + assert(r3_1 == r3_2) + validateOffsetImpliesMoveBits(r1_1.base.bitStream, diff) + assert(r2_2 == r1_1.withMovedBitIndex(diff)) + // TODO: Exported symbol not working + // val (r2Got_2, vGot_2) = r2_2.readNLeastSignificantBitsLoopPure(nBits, 0, 0L) + val (r2Got_2, vGot_2) = r2_2.base.bitStream.readNLeastSignificantBitsLoopPure(nBits, 0, 0L) + assert(vGot_2 == intVal.toRaw) + + val (r3Got_3, vGot_3) = r1_1.base.bitStream.readNLeastSignificantBitsLoopPure(encodedSizeInBits, 0, 0L) + assert(iGot.toRaw == vGot_3) + assert(r3Got.base.bitStream == r3Got_3) + checkBitsLoopAndReadNLSB(r1_1.base.bitStream, diff, false) + readNLeastSignificantBitsLeadingZerosLemma(r1_1.base.bitStream, encodedSizeInBits, diff) + check(iGot == intVal) + check(r3Got == r3_1) + } else { + check(iGot == intVal) + check(r3Got == r3_1) + } + }*/ + } /*else { + ghostExpr { + validReflexiveLemma(bitStream) + } + }*/ + }.ensuring { _ => + val w1 = old(this) + val w3 = this + w1.base.bitStream.buf.length == w3.base.bitStream.buf.length && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + encodedSizeInBits + /*&& w1.isPrefixOf(w3) && { + val (r1, r3) = ACN.reader(w1, w3) + validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, encodedSizeInBits) + val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_pure(encodedSizeInBits) + iGot == intVal && r3Got == r3 + }*/ } @ghost @pure @inline - def resetAt(other: ACN): ACN = + def resetAt(other: ACN): ACN = { + require(bitStream.buf.length == other.base.bitStream.buf.length) ACN(Codec(bitStream.resetAt(other.base.bitStream))) + } @ghost @pure @inline def withMovedByteIndex(diffInBytes: Int): ACN = { @@ -247,284 +315,308 @@ case class ACN(base: Codec) { ACN(Codec(bitStream.withMovedBitIndex(diffInBits))) } - @pure @inline - def bitIndex(): Long = bitStream.bitIndex() - - @pure @inline - def bufLength(): Int = bitStream.buf.length - - @pure @inline - def validate_offset_bits(bits: Long = 0): Boolean = { - require(bits >= 0) - bitStream.validate_offset_bits(bits) - } - @pure @inline def isPrefixOf(acn2: ACN): Boolean = bitStream.isPrefixOf(acn2.base.bitStream) + @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_8(intVal: ULong): Unit = { - require(bitStream.validate_offset_byte()) + require(BitStream.validate_offset_byte(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit)) + require(intVal <= 255) appendByte(wrappingExpr { intVal.toUByte }) + }.ensuring { _ => + val w1 = old(this) + val w2 = this + w1.base.bufLength() == w2.base.bufLength() && BitStream.bitIndex(w2.base.bitStream.buf.length, w2.base.bitStream.currentByte, w2.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 8 /*&& w1.isPrefixOf(w2) && { + val (r1, r2) = ACN.reader(w1, w2) + val (r2Got, vGot) = r1.dec_Int_PositiveInteger_ConstSize_8_pure() + vGot == intVal && r2Got == r2 + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_big_endian_16(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) require(uintVal <= 65535) val intVal = uintVal.toRaw assert((intVal >> 16) == 0L) - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) appendByte(wrappingExpr { (intVal >> 8).toByte.toRawUByte }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) appendByte(wrappingExpr { intVal.toByte.toRawUByte }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first byte gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.base.bitStream.resetAt(this1.base.bitStream) readBytePrefixLemma(this2Reset, this.base.bitStream) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 16 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 16 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 16) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_big_endian_16_pure() iGot == uintVal && r3Got == r3 - } + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_big_endian_32(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) require(uintVal <= 4294967295L) val intVal = uintVal.toRaw assert((intVal >> 32) == 0L) - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) enc_Int_PositiveInteger_ConstSize_big_endian_16(wrappingExpr { ((intVal >> 16) & 0xFFFFL).toRawULong }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) enc_Int_PositiveInteger_ConstSize_big_endian_16(wrappingExpr { (intVal & 0xFFFFL).toRawULong }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first integer gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.resetAt(this1) dec_Int_PositiveInteger_ConstSize_big_endian_16_prefixLemma(this2Reset, this) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 32 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 32 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 32) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_big_endian_32_pure() iGot == uintVal && r3Got == r3 - } + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_big_endian_64(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val intVal = uintVal.toRaw - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) enc_Int_PositiveInteger_ConstSize_big_endian_32(wrappingExpr { ((intVal >> 32) & 0xFFFFFFFFL).toRawULong }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) enc_Int_PositiveInteger_ConstSize_big_endian_32(wrappingExpr { (intVal & 0xFFFFFFFFL).toRawULong }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first integer gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.resetAt(this1) dec_Int_PositiveInteger_ConstSize_big_endian_32_prefixLemma(this2Reset, this) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 64 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 64 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 64) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_big_endian_64_pure() iGot == uintVal && r3Got == r3 - } + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_little_endian_16(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) require(uintVal <= 65535) val intVal = uintVal.toRaw assert((intVal >> 16) == 0L) - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) appendByte(wrappingExpr { intVal.toUByte }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) appendByte(wrappingExpr { (intVal >> 8).toUByte }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first byte gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.resetAt(this1) readBytePrefixLemma(this2Reset.base.bitStream, this.base.bitStream) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 16 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 16 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 16) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_little_endian_16_pure() iGot == uintVal && r3Got == r3 - } + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_little_endian_32(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) require(uintVal <= 4294967295L) val intVal = uintVal.toRaw assert((intVal >> 32) == 0L) - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) enc_Int_PositiveInteger_ConstSize_little_endian_16(wrappingExpr { (intVal & 0xFFFFL).toRawULong }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) enc_Int_PositiveInteger_ConstSize_little_endian_16(wrappingExpr { ((intVal >> 16) & 0xFFFFL).toRawULong }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first integer gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.resetAt(this1) dec_Int_PositiveInteger_ConstSize_little_endian_16_prefixLemma(this2Reset, this) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 32 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 32 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 32) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_little_endian_32_pure() iGot == uintVal && r3Got == r3 - } + }*/ } @opaque @inlineOnce def enc_Int_PositiveInteger_ConstSize_little_endian_64(uintVal: ULong): Unit = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val intVal = uintVal.toRaw - @ghost val this1 = snapshot(this) + // @ghost val this1 = snapshot(this) enc_Int_PositiveInteger_ConstSize_little_endian_32(wrappingExpr { (intVal & 0xFFFFFFFFL).toRawULong }) - @ghost val this2 = snapshot(this) + // @ghost val this2 = snapshot(this) enc_Int_PositiveInteger_ConstSize_little_endian_32(wrappingExpr { ((intVal >> 32) & 0xFFFFFFFFL).toRawULong }) - ghostExpr { + /*ghostExpr { // For isPrefix validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) // Reading back the first integer gives the same result whether we are reading from this2 or the end result this val this2Reset = this2.resetAt(this1) dec_Int_PositiveInteger_ConstSize_little_endian_32_prefixLemma(this2Reset, this) - } + }*/ }.ensuring { _ => val w1 = old(this) val w3 = this - w1.bufLength() == w3.bufLength() && w3.bitIndex() == w1.bitIndex() + 64 && w1.isPrefixOf(w3) && { + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + 64 /*&& w1.isPrefixOf(w3) && { val (r1, r3) = ACN.reader(w1, w3) validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, 64) val (r3Got, iGot) = r1.dec_Int_PositiveInteger_ConstSize_little_endian_64_pure() iGot == uintVal && r3Got == r3 - } + }*/ } def dec_Int_PositiveInteger_ConstSize(encodedSizeInBits: Int): ULong = { + require(encodedSizeInBits >= 0 && encodedSizeInBits <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) decodeUnsignedInteger(encodedSizeInBits) } + @ghost @pure + def dec_Int_PositiveInteger_ConstSize_pure(encodedSizeInBits: Int): (ACN, ULong) = { + require(encodedSizeInBits >= 0 && encodedSizeInBits <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) + val cpy = snapshot(this) + val l = cpy.dec_Int_PositiveInteger_ConstSize(encodedSizeInBits) + (cpy, l) + } + + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_8(): ULong = { - require(bitStream.validate_offset_byte()) - (readByte().toRaw & 0xFF).toULong + require(BitStream.validate_offset_byte(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit)) + ULong.fromRaw(readByte().toRaw & 0xFF) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 8) + + @ghost @pure + def dec_Int_PositiveInteger_ConstSize_8_pure(): (ACN, ULong) = { + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 8)) + val cpy = snapshot(this) + val l = cpy.dec_Int_PositiveInteger_ConstSize_8() + (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_16(): ULong = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) val b1 = readByte().toRaw val b2 = readByte().toRaw ULong.fromRaw((((b1.toLong << 8) & 0xFF00L) | (b2.toLong & 0xFFL)) & 0xFFFFL) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 16) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 16) @ghost @pure def dec_Int_PositiveInteger_ConstSize_big_endian_16_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_big_endian_16() (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_32(): ULong = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) val i1 = dec_Int_PositiveInteger_ConstSize_big_endian_16().toRaw val i2 = dec_Int_PositiveInteger_ConstSize_big_endian_16().toRaw ULong.fromRaw((((i1.toLong << 16) & 0xFFFF0000L) | (i2.toLong & 0xFFFFL)) & 0xFFFFFFFFL) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 32) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 32) @ghost @pure def dec_Int_PositiveInteger_ConstSize_big_endian_32_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_big_endian_32() (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_big_endian_64(): ULong = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val i1 = dec_Int_PositiveInteger_ConstSize_big_endian_32().toRaw val i2 = dec_Int_PositiveInteger_ConstSize_big_endian_32().toRaw ULong.fromRaw(((i1.toLong << 32) & 0xFFFFFFFF00000000L) | (i2.toLong & 0xFFFFFFFFL)) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 64) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 64) @ghost @pure def dec_Int_PositiveInteger_ConstSize_big_endian_64_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_big_endian_64() (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_16(): ULong = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) val b1 = readByte().toRaw val b2 = readByte().toRaw ULong.fromRaw((((b2.toLong << 8) & 0xFF00L) | (b1.toLong & 0xFFL)) & 0xFFFFL) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 16) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 16) @ghost @pure def dec_Int_PositiveInteger_ConstSize_little_endian_16_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(16)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_little_endian_16() (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_32(): ULong = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) val i1 = dec_Int_PositiveInteger_ConstSize_little_endian_16().toRaw val i2 = dec_Int_PositiveInteger_ConstSize_little_endian_16().toRaw ULong.fromRaw((((i2.toLong << 16) & 0xFFFF0000L) | (i1.toLong & 0xFFFFL)) & 0xFFFFFFFFL) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 32) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 32) @ghost @pure def dec_Int_PositiveInteger_ConstSize_little_endian_32_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(32)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_little_endian_32() (cpy, l) } + @opaque @inlineOnce def dec_Int_PositiveInteger_ConstSize_little_endian_64(): ULong = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val i1 = dec_Int_PositiveInteger_ConstSize_little_endian_32().toRaw val i2 = dec_Int_PositiveInteger_ConstSize_little_endian_32().toRaw ULong.fromRaw(((i2.toLong << 32) & 0xFFFFFFFF00000000L) | (i1.toLong & 0xFFFFFFFFL)) - }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && bitStream.bitIndex() == old(this).base.bitStream.bitIndex() + 64) + }.ensuring(_ => bitStream.buf == old(this).base.bitStream.buf && BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + 64) @ghost @pure def dec_Int_PositiveInteger_ConstSize_little_endian_64_pure(): (ACN, ULong) = { - require(bitStream.validate_offset_bits(64)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) val cpy = snapshot(this) val l = cpy.dec_Int_PositiveInteger_ConstSize_little_endian_64() (cpy, l) @@ -588,45 +680,123 @@ case class ACN(base: Codec) { * @param v value that gets encoded * @param formatBitLength number of dataformat bits */ + @opaque @inlineOnce def enc_Int_TwosComplement_ConstSize(v: Long, formatBitLength: Int): Unit = { - require(GetBitCountSigned(v) <= formatBitLength) // TODO check with stainless - - // add additional bits if formatBitLength is bigger than 64 - val addedBits = max(0, formatBitLength - NO_OF_BITS_IN_LONG) - if v >= 0 then appendNZeroBits(addedBits) else appendNOneBits(addedBits) + val nBits = GetBitCountSigned(v) + require(nBits <= formatBitLength && formatBitLength <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, formatBitLength)) - appendNLeastSignificantBits(v, min(NO_OF_BITS_IN_LONG, formatBitLength)) - }.ensuring(_ => true) // TODO + val addedBits = formatBitLength - nBits + @ghost val this1 = snapshot(this) + appendNBits(addedBits, v < 0) + ghostExpr { + validateOffsetBitsDifferenceLemma(this1.base.bitStream, this.base.bitStream, formatBitLength, addedBits) + } + // @ghost val this2 = snapshot(this) + appendNLeastSignificantBits(v & onesLSBLong(nBits), nBits) + /*ghostExpr { + assert(BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(this2.base.bitStream.buf.length, this2.base.bitStream.currentByte, this2.base.bitStream.currentBit) + nBits) + assert(BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) == BitStream.bitIndex(this1.base.bitStream.buf.length, this1.base.bitStream.currentByte, this1.base.bitStream.currentBit) + formatBitLength) + validTransitiveLemma(this1.base.bitStream, this2.base.bitStream, this.base.bitStream) + val this2Reset = this2.resetAt(this1) + val (r1_1, r3_1) = ACN.reader(this1, this) + validateOffsetBitsContentIrrelevancyLemma(this1.base.bitStream, this.base.bitStream.buf, formatBitLength) + val (r3Got, vGot) = r1_1.dec_Int_TwosComplement_ConstSize_pure(formatBitLength) + + if (formatBitLength != nBits) { + checkBitsLoopPrefixLemma2(this2Reset.base.bitStream, this.base.bitStream, addedBits, v < 0, 0) + + val (r2_2, r3_2) = ACN.reader(this2, this) + assert(r3_1 == r3_2) + validateOffsetImpliesMoveBits(r1_1.base.bitStream, addedBits) + assert(r2_2 == r1_1.withMovedBitIndex(addedBits)) + val (r2Got_2, vGot_2) = r2_2.base.bitStream.readNLeastSignificantBitsLoopPure(nBits, 0, 0L) + assert(vGot_2 == (v & onesLSBLong(nBits))) + + val (r3Got_3, vGot_3) = r1_1.base.bitStream.readNLeastSignificantBitsLoopPure(formatBitLength, 0, 0L) + + checkBitsLoopAndReadNLSB(r1_1.base.bitStream, addedBits, v < 0) + readNLeastSignificantBitsLeadingBitsLemma(r1_1.base.bitStream, v < 0, formatBitLength, addedBits) + assert(vGot == (bitMSBLong(v < 0, NO_OF_BITS_IN_LONG - formatBitLength) | vGot_3)) + assert(r3Got.base.bitStream == r3Got_3) + assert(((vGot_3 & (1L << (formatBitLength - 1))) == 0L) == v >= 0) + if (v < 0) { + assert((v & (1L << (formatBitLength - 1))) != 0L) + check(vGot == v) + } else { + assert((v & onesLSBLong(nBits)) == v) + assert(formatBitLength == 0 || (v & (1L << (formatBitLength - 1))) == 0L) + check(vGot == v) + } + check(r3Got == r3_1) + } else { + if (v < 0) { + assert((onesMSBLong(NO_OF_BITS_IN_LONG - nBits) | (v & onesLSBLong(nBits))) == v) + assert(((v & onesLSBLong(nBits)) & (1L << (nBits - 1))) != 0L) + check(vGot == v) + } else { + assert((v & onesLSBLong(nBits)) == v) + assert(nBits == 0 || (v & (1L << (nBits - 1))) == 0L) + check(vGot == v) + } + check(vGot == v) + check(r3Got == r3_1) + } + }*/ + }.ensuring { _ => + val w1 = old(this) + val w3 = this + w1.base.bufLength() == w3.base.bufLength() && BitStream.bitIndex(w3.base.bitStream.buf.length, w3.base.bitStream.currentByte, w3.base.bitStream.currentBit) == BitStream.bitIndex(w1.base.bitStream.buf.length, w1.base.bitStream.currentByte, w1.base.bitStream.currentBit) + formatBitLength /*&& w1.isPrefixOf(w3) && { + val (r1, r3) = ACN.reader(w1, w3) + validateOffsetBitsContentIrrelevancyLemma(w1.base.bitStream, w3.base.bitStream.buf, formatBitLength) + val (r3Got, vGot) = r1.dec_Int_TwosComplement_ConstSize_pure(formatBitLength) + vGot == v && r3Got == r3 + }*/ + } def enc_Int_TwosComplement_ConstSize_8(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_8(int2uint(intVal)) + require(BitStream.validate_offset_byte(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit)) + require(-128L <= intVal && intVal <= 127L) + enc_Int_PositiveInteger_ConstSize_8(ULong.fromRaw(intVal & 0xFFL)) } def enc_Int_TwosComplement_ConstSize_big_endian_16(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_big_endian_16(int2uint(intVal)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16)) + require(-32768L <= intVal && intVal <= 32767L) + enc_Int_PositiveInteger_ConstSize_big_endian_16(ULong.fromRaw(intVal & 0xFFFFL)) } def enc_Int_TwosComplement_ConstSize_big_endian_32(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_big_endian_32(int2uint(intVal)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) + require(-2147483648L <= intVal && intVal <= 2147483647L) + enc_Int_PositiveInteger_ConstSize_big_endian_32(ULong.fromRaw(intVal & 0xFFFFFFFFL)) } def enc_Int_TwosComplement_ConstSize_big_endian_64(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_big_endian_64(int2uint(intVal)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) + enc_Int_PositiveInteger_ConstSize_big_endian_64(ULong.fromRaw(intVal)) } def enc_Int_TwosComplement_ConstSize_little_endian_16(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_little_endian_16(int2uint(intVal)) + enc_Int_PositiveInteger_ConstSize_little_endian_16(ULong.fromRaw(intVal)) } def enc_Int_TwosComplement_ConstSize_little_endian_32(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_little_endian_32(int2uint(intVal)) + enc_Int_PositiveInteger_ConstSize_little_endian_32(ULong.fromRaw(intVal)) } def enc_Int_TwosComplement_ConstSize_little_endian_64(intVal: Long): Unit = { - enc_Int_PositiveInteger_ConstSize_little_endian_64(int2uint(intVal)) + enc_Int_PositiveInteger_ConstSize_little_endian_64(ULong.fromRaw(intVal)) } def dec_Int_TwosComplement_ConstSize(encodedSizeInBits: Int): Long = { + require(encodedSizeInBits >= 0 && encodedSizeInBits <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) + + val res = readNLeastSignificantBits(encodedSizeInBits) + if encodedSizeInBits == 0 || (res & (1L << (encodedSizeInBits - 1))) == 0L then res + else onesMSBLong(NO_OF_BITS_IN_LONG - encodedSizeInBits) | res + /* val valIsNegative = peekBit() val nBytes: Int = encodedSizeInBits / 8 @@ -645,35 +815,67 @@ case class ACN(base: Codec) { pIntVal = (pIntVal << rstBits) | (readPartialByte(rstBits.toByte).toRaw & 0xFF) pIntVal + */ + } + + @ghost @pure + def dec_Int_TwosComplement_ConstSize_pure(encodedSizeInBits: Int): (ACN, Long) = { + require(encodedSizeInBits >= 0 && encodedSizeInBits <= NO_OF_BITS_IN_LONG) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, encodedSizeInBits)) + + val cpy = snapshot(this) + val l = cpy.dec_Int_TwosComplement_ConstSize(encodedSizeInBits) + (cpy, l) } def dec_Int_TwosComplement_ConstSize_8(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_8(), 1) + if(!BitStream.validate_offset_byte(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) ) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_8(), 1) } def dec_Int_TwosComplement_ConstSize_big_endian_16(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_16(), NO_OF_BYTES_IN_JVM_SHORT) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16) ) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_16(), NO_OF_BYTES_IN_JVM_SHORT) } def dec_Int_TwosComplement_ConstSize_big_endian_32(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_32(), NO_OF_BYTES_IN_JVM_INT) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_32(), NO_OF_BYTES_IN_JVM_INT) } def dec_Int_TwosComplement_ConstSize_big_endian_64(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_64(), NO_OF_BYTES_IN_JVM_LONG) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_big_endian_64(), NO_OF_BYTES_IN_JVM_LONG) } def dec_Int_TwosComplement_ConstSize_little_endian_16(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_16(), NO_OF_BYTES_IN_JVM_SHORT) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 16) ) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_16(), NO_OF_BYTES_IN_JVM_SHORT) } def dec_Int_TwosComplement_ConstSize_little_endian_32(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_32(), NO_OF_BYTES_IN_JVM_INT) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 32)) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_32(), NO_OF_BYTES_IN_JVM_INT) } def dec_Int_TwosComplement_ConstSize_little_endian_64(): Long = { - uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_64(), NO_OF_BYTES_IN_JVM_LONG) + if(!BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, 64)) then + 0L + else + uint2int(dec_Int_PositiveInteger_ConstSize_little_endian_64(), NO_OF_BYTES_IN_JVM_LONG) } def enc_Int_TwosComplement_VarSize_LengthEmbedded(intVal: Long): Unit = { @@ -993,25 +1195,76 @@ case class ACN(base: Codec) { /* Boolean Decode */ // TODO move to codec? + @opaque @inlineOnce def BitStream_ReadBitPattern(patternToRead: Array[UByte], nBitsToRead: Int): Boolean = { + require(nBitsToRead < Int.MaxValue - 8) + require(nBitsToRead >= 0) + require(patternToRead.length >= nBitsToRead / 8 + (if (nBitsToRead % 8 == 0) then 0 else 1)) + require(BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, nBitsToRead)) val nBytesToRead: Int = nBitsToRead / 8 val nRemainingBitsToRead: Int = nBitsToRead % 8 + val neededBytes = nBytesToRead + (if (nRemainingBitsToRead == 0) then 0 else 1) + @ghost val oldThis = snapshot(this) var pBoolValue: Boolean = true var i: Int = 0 + + + assert(i >= 0 ) + assert(i <= nBytesToRead ) + assert(nBitsToRead < Int.MaxValue ) + assert(neededBytes <= patternToRead.length) + assert(neededBytes == nBytesToRead || neededBytes == nBytesToRead + 1) + assert(nBytesToRead <= Int.MaxValue / 8) + assert(neededBytes <= Int.MaxValue / 8) + (while i < nBytesToRead do decreases(nBytesToRead - i) - if readByte() != patternToRead(i) then + @ghost val oldThisLoop = snapshot(this) + @ghost val oldBufLen = base.bitStream.buf.length + @ghost val oldCurrentByte = base.bitStream.currentByte + @ghost val oldCurrentBit = base.bitStream.currentBit + @ghost val oldBitIndex = BitStream.bitIndex(oldBufLen, oldCurrentByte, oldCurrentBit) + val read = { + val remaining = BitStream.remainingBits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) + if (remaining < 8) readPartialByte(remaining.toInt) + else readByte() + } + if read != patternToRead(i) then pBoolValue = false + + ghostExpr { + assert(BitStream.bitIndex(oldBufLen, oldCurrentByte, oldCurrentBit) + 8 >= BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit)) + @ghost val bitIndex = BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) + assert(bitIndex == oldBitIndex + 8) + BitStream.validateOffsetBitsIneqLemma(oldThisLoop.base.bitStream, base.bitStream, nBitsToRead - i * 8L, 8L) + } i += 1 - ).invariant(true) // TODO + ).opaque.inline.invariant( + i >= 0 &&& + i <= nBytesToRead &&& + nBitsToRead < Int.MaxValue &&& + neededBytes <= patternToRead.length &&& + neededBytes >= nBytesToRead &&& + neededBytes <= Int.MaxValue / 8 &&& + nBytesToRead <= Int.MaxValue / 8 &&& + base.bitStream.buf == oldThis.base.bitStream.buf && base.bitStream.currentByte >= 0 && base.bitStream.currentBit >= 0 &&& + BitStream.invariant(base.bitStream) &&& + BitStream.bitIndex(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit) <= BitStream.bitIndex(oldThis.base.bitStream.buf.length, oldThis.base.bitStream.currentByte, oldThis.base.bitStream.currentBit) + i * 8L &&& + BitStream.validate_offset_bits(base.bitStream.buf.length, base.bitStream.currentByte, base.bitStream.currentBit, nBitsToRead - i * 8L) + ) + if nRemainingBitsToRead > 0 then if readPartialByte(nRemainingBitsToRead.toByte).toRaw != ((patternToRead(nBytesToRead).toRaw & 0xFF) >>> (8 - nRemainingBitsToRead)) then pBoolValue = false + assert(nBytesToRead.toLong * 8L + nRemainingBitsToRead.toLong == nBitsToRead) + ghostExpr { check(BitStream.bitIndex(this.base.bitStream.buf.length, this.base.bitStream.currentByte, this.base.bitStream.currentBit) <= BitStream.bitIndex(oldThis.base.bitStream.buf.length, oldThis.base.bitStream.currentByte, oldThis.base.bitStream.currentBit) + nBitsToRead) } + + assert(BitStream.bitIndex(this.base.bitStream.buf.length, this.base.bitStream.currentByte, this.base.bitStream.currentBit) <= BitStream.bitIndex(oldThis.base.bitStream.buf.length, oldThis.base.bitStream.currentByte, oldThis.base.bitStream.currentBit) + nBitsToRead) pBoolValue - } + }.ensuring(_ => buf == old(this).base.bitStream.buf && BitStream.bitIndex(this.base.bitStream.buf.length, this.base.bitStream.currentByte, this.base.bitStream.currentBit) <= BitStream.bitIndex(old(this).base.bitStream.buf.length, old(this).base.bitStream.currentByte, old(this).base.bitStream.currentBit) + nBitsToRead) // TODO move to codec? def BitStream_ReadBitPattern_ignore_value(nBitsToRead: Int): Unit = { @@ -1185,29 +1438,52 @@ case class ACN(base: Codec) { i += 1 } + @opaque @inlineOnce def enc_String_CharIndex_private(max: Long, allowedCharSet: Array[UByte], strVal: Array[ASCIIChar]): Long = { + // Does not make sense to have a max variable of type Long, as the index of an array must be an Int + require(max < Int.MaxValue && max >= 0) + require(allowedCharSet.length > 0) + @ghost val oldThis = snapshot(this) var i: Int = 0 - while (i < max) && (strVal(i).toRaw != CHAR_0000) do + // SAM Here I put a dynamic check for the buffer size, because the buffer size depends on when the CHAR_0000 is found, and it does + // not make sense to require a buffer of size max, and I decided to return -1L if one of the checkes fails + val nBitsPerElmt = GetBitCountUnsigned(stainless.math.wrapping(allowedCharSet.length - 1).toRawULong) + (while (i < max) && (i < strVal.length) && (strVal(i).toRaw != CHAR_0000) do + decreases(max - i) + if((i >= strVal.length) ) then + return -1L val charIndex: Int = GetCharIndex(strVal(i), allowedCharSet) + if(!BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nBitsPerElmt)) then + return -1L encodeConstrainedWholeNumber(charIndex, 0, allowedCharSet.length - 1) i += 1 + ).invariant( + i <= max && i >= 0 && + max <= Int.MaxValue && + i <= strVal.length && + base.bitStream.buf.length == oldThis.base.bitStream.buf.length + ) - i - } - + i.toLong + }.ensuring(_ => base.bitStream.buf.length == old(this).base.bitStream.buf.length) + @opaque @inlineOnce def enc_String_CharIndex_External_Field_Determinant(max: Long, allowedCharSet: Array[UByte], strVal: Array[ASCIIChar]): Unit = { enc_String_CharIndex_private(max, allowedCharSet, strVal) - } + () + }.ensuring(_ => base.bitStream.buf.length == old(this).base.bitStream.buf.length) + @opaque @inlineOnce def enc_String_CharIndex_Internal_Field_Determinant(max: Long, allowedCharSet: Array[UByte], min: Long, strVal: Array[ASCIIChar]): Unit = { val strLen: Int = strVal.length encodeConstrainedWholeNumber(if strLen <= max then strLen else max, min, max) enc_String_CharIndex_private(max, allowedCharSet, strVal) - } - + () + }.ensuring(_ => base.bitStream.buf.length == old(this).base.bitStream.buf.length) + @opaque @inlineOnce def enc_IA5String_CharIndex_External_Field_Determinant(max: Long, strVal: Array[ASCIIChar]): Unit = { + require(max < Int.MaxValue && max >= 0) val allowedCharSet: Array[Byte] = Array( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, @@ -1225,8 +1501,10 @@ case class ACN(base: Codec) { ) enc_String_CharIndex_private(max, UByte.fromArrayRaws(allowedCharSet), strVal) - } + () + }.ensuring(_ => base.bitStream.buf.length == old(this).base.bitStream.buf.length) + @opaque @inlineOnce def enc_IA5String_CharIndex_Internal_Field_Determinant(max: Long, min: Long, strVal: Array[ASCIIChar]): Unit = { val allowedCharSet: Array[Byte] = Array( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, @@ -1246,7 +1524,8 @@ case class ACN(base: Codec) { val strLen: Int = strVal.length encodeConstrainedWholeNumber(if strLen <= max then strLen else max, min, max) enc_String_CharIndex_private(max, UByte.fromArrayRaws(allowedCharSet), strVal) - } + () + }.ensuring(_ => base.bitStream.buf.length == old(this).base.bitStream.buf.length) def dec_String_Ascii_private(max: Long, charactersToDecode: Long): Array[ASCIIChar] = { @@ -1315,26 +1594,48 @@ case class ACN(base: Codec) { } + @opaque @inlineOnce def dec_String_Ascii_External_Field_Determinant(max: Long, extSizeDeterminantFld: Long): Array[ASCIIChar] = { dec_String_Ascii_private(max, if extSizeDeterminantFld <= max then extSizeDeterminantFld else max) - } + }.ensuring(_ => base.bitStream.buf == old(this).base.bitStream.buf) + @opaque @inlineOnce def dec_String_Ascii_Internal_Field_Determinant(max: Long, min: Long): Array[ASCIIChar] = { val nCount = decodeConstrainedWholeNumber(min, max) dec_String_Ascii_private(max, if nCount <= max then nCount else max) - } + }.ensuring(_ => base.bitStream.buf == old(this).base.bitStream.buf) + @opaque @inlineOnce def dec_String_CharIndex_private(max: Long, charactersToDecode: Long, allowedCharSet: Array[UByte]): Array[ASCIIChar] = { + require(allowedCharSet.length > 0) + require(max < Int.MaxValue && max >= 0) + require(charactersToDecode >= 0 && charactersToDecode <= max) + @ghost val oldThis = snapshot(this) val strVal: Array[ASCIIChar] = Array.fill(max.toInt + 1)(0.toRawUByte) var i: Int = 0 - (while i < charactersToDecode do + assert(allowedCharSet.length > 0) + assert(strVal.length > 0) + assert(strVal.length > max) + assert(strVal.length > charactersToDecode) + assert(i < strVal.length) + + val nBitsPerElmt = GetBitCountUnsigned(stainless.math.wrapping(allowedCharSet.length - 1).toRawULong) + (while i < charactersToDecode do decreases(charactersToDecode - i) + if(!BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, nBitsPerElmt)) + return Array.empty strVal(i) = allowedCharSet(decodeConstrainedWholeNumber(0, allowedCharSet.length - 1).toInt) i += 1 - ).invariant(true) // TODO + ).invariant( + i <= charactersToDecode && i >= 0 && + charactersToDecode < Int.MaxValue && + i < strVal.length && + max < strVal.length && + base.bitStream.buf == oldThis.base.bitStream.buf + ) strVal - } + }.ensuring(_ => base.bitStream.buf == old(this).base.bitStream.buf) def dec_String_CharIndex_FixSize(max: Long, allowedCharSet: Array[ASCIIChar]): Array[ASCIIChar] = { dec_String_CharIndex_private(max, max, allowedCharSet) @@ -1351,7 +1652,11 @@ case class ACN(base: Codec) { } + @opaque @inlineOnce def dec_IA5String_CharIndex_External_Field_Determinant(max: Long, extSizeDeterminantFld: Long): Array[ASCIIChar] = { + require(max < Int.MaxValue) + require(extSizeDeterminantFld >= 0) + require(max >= 0) // SAM Check whether this is correct, otherwise transform it into a runtime check val allowedCharSet: Array[Byte] = Array( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, @@ -1368,9 +1673,13 @@ case class ACN(base: Codec) { 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F ) dec_String_CharIndex_private(max, if extSizeDeterminantFld <= max then extSizeDeterminantFld else max, UByte.fromArrayRaws(allowedCharSet)) - } + }.ensuring(_ => base.bitStream.buf == old(this).base.bitStream.buf) def dec_IA5String_CharIndex_Internal_Field_Determinant(max: Long, min: Long): Array[ASCIIChar] = { + require(min <= max) + require(max < Int.MaxValue) + require(max >= 0) + require(min >= 0) // SAM Check whether this is correct, otherwise transform it into a runtime check val allowedCharSet: Array[Byte] = Array( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, @@ -1386,9 +1695,13 @@ case class ACN(base: Codec) { 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F ) + if(!BitStream.validate_offset_bits(bitStream.buf.length, bitStream.currentByte, bitStream.currentBit, GetBitCountUnsigned(stainless.math.wrapping(max - min).toRawULong))) + return Array.empty val nCount = decodeConstrainedWholeNumber(min, max) - dec_String_CharIndex_private(max, if nCount <= max then nCount else max, UByte.fromArrayRaws(allowedCharSet)) - } + val charToDecode = if nCount <= max then nCount else max + assert(charToDecode >= 0 && charToDecode <= max) + dec_String_CharIndex_private(max, charToDecode, UByte.fromArrayRaws(allowedCharSet)) + }.ensuring(_ => base.bitStream.buf == old(this).base.bitStream.buf) /* Length Determinant functions*/ diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_PER.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_PER.scala index 2315f96c5..3328913f8 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_PER.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_PER.scala @@ -1,6 +1,9 @@ package asn1scala +import stainless.lang.StaticChecks._ +import stainless.annotation._ +// SAM ignored for the safety checks /** * Get an instance of a PER coded bitstream * @param count of elements in underlying buffer @@ -11,5 +14,27 @@ def initPERCodec(count: Int): PER = { } case class PER private [asn1scala](base: Codec) { - export base.* + import BitStream.* + export base.{isPrefixOf => _, withMovedBitIndex => _, withMovedByteIndex => _, *} + + @ghost @pure @inline + def resetAt(other: PER): PER = { + require(bitStream.buf.length == other.base.bitStream.buf.length) + PER(Codec(bitStream.resetAt(other.base.bitStream))) + } + + @ghost @pure @inline + def withMovedByteIndex(diffInBytes: Int): PER = { + require(moveByteIndexPrecond(bitStream, diffInBytes)) + PER(Codec(bitStream.withMovedByteIndex(diffInBytes))) + } + + @ghost @pure @inline + def withMovedBitIndex(diffInBits: Int): PER = { + require(moveBitIndexPrecond(bitStream, diffInBits)) + PER(Codec(bitStream.withMovedBitIndex(diffInBits))) + } + + @pure @inline + def isPrefixOf(per2: PER): Boolean = bitStream.isPrefixOf(per2.base.bitStream) } diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_UPER.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_UPER.scala index f65a2ada5..e4173a336 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_UPER.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Codec_UPER.scala @@ -5,13 +5,20 @@ import stainless.lang.StaticChecks._ import stainless.lang.{None => None, Option => Option, Some => Some, _} import stainless.annotation._ + +// SAM Ignored for safety verification + /** * Get an instance of a UPER coded bitstream * @param count of elements in underlaying buffer * @return UPER coded bitstream */ def initUPERCodec(count: Int): UPER = { - UPER(Codec(BitStream(Array.fill(count)(0)))) + //SAM guard to ensure the property + if count <= 0 then + UPER(Codec(BitStream(Array.fill(0)(0)))) + else + UPER(Codec(BitStream(Array.fill(count)(0)))) } object UPER { @ghost @pure @@ -25,11 +32,12 @@ case class UPER private [asn1scala](base: Codec) { import BitStream.* import UPER.* import base.* - export base.* @ghost @pure @inline - def resetAt(other: UPER): UPER = + def resetAt(other: UPER): UPER = { + require(bitStream.buf.length == other.base.bitStream.buf.length) UPER(Codec(bitStream.resetAt(other.base.bitStream))) + } @ghost @pure @inline def withMovedByteIndex(diffInBytes: Int): UPER = { @@ -43,18 +51,6 @@ case class UPER private [asn1scala](base: Codec) { UPER(Codec(bitStream.withMovedBitIndex(diffInBits))) } - @pure @inline - def bitIndex(): Long = bitStream.bitIndex() - - @pure @inline - def bufLength(): Int = bitStream.buf.length - - @pure @inline - def validate_offset_bits(bits: Long = 0): Boolean = { - require(bits >= 0) - bitStream.validate_offset_bits(bits) - } - @pure @inline def isPrefixOf(uper2: UPER): Boolean = bitStream.isPrefixOf(uper2.base.bitStream) diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Helper.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Helper.scala index f37a6cda5..710351811 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Helper.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Helper.scala @@ -30,6 +30,18 @@ val MASK_C: Array[Byte] = Array( -0x08, // / 1111 1000 / -0x04, // / 1111 1100 / -0x02, // / 1111 1110 / + -0x01, // / 1111 1111 / +) + +val BitAccessMasks: Array[Byte] = Array( + -0x80, // -128 / 1000 0000 / x80 + 0x40, // 64 / 0100 0000 / x40 + 0x20, // 32 / 0010 0000 / x20 + 0x10, // 16 / 0001 0000 / x10 + 0x08, // 8 / 0000 1000 / x08 + 0x04, // 4 / 0000 0100 / x04 + 0x02, // 2 / 0000 0010 / x02 + 0x01, // 1 / 0000 0001 / x01 ) extension [T](arr: Array[T]) { @@ -88,7 +100,7 @@ def GetBitCountUnsigned(vv: ULong): Int = { x >= 0 && x <= NO_OF_BITS_IN_LONG && (x == NO_OF_BITS_IN_LONG && vv.toRaw < 0 || vv.toRaw >>> x == 0)) /** - * Get number of bits needed to encode the singed value v + * Get number of bits needed to encode the signed value v * * Example: * 5 bit (include sign bit) @@ -108,9 +120,13 @@ def GetBitCountSigned(v: Long): Int = { ).invariant(i >= 1 && i <= NO_OF_BITS_IN_LONG) i - -}.ensuring(x => - x >= 0 && x <= NO_OF_BITS_IN_LONG) +}.ensuring { nBits => + 0 <= nBits && nBits <= NO_OF_BITS_IN_LONG && + ((v < 0) ==> + ((onesMSBLong(NO_OF_BITS_IN_LONG - nBits) | (v & onesLSBLong(nBits))) == v && + ((v & onesLSBLong(nBits)) & (1L << (nBits - 1))) != 0L)) && + ((v >= 0) ==> ((v & onesLSBLong(nBits)) == v && (v & (1L << (nBits - 1))) == 0L)) +} /** * Get number of bytes needed to represent the value v @@ -226,8 +242,8 @@ def CalculateMantissaAndExponent(doubleAsLong64: Long): (UInt, ULong) = { (UInt.fromRaw(exponent), ULong.fromRaw(mantissa)) -}.ensuring((e, m) => (-DoubleBias - DoubleNoOfMantissaBits).toInt.toRawUInt <= e &&& e <= (DoubleBias - DoubleNoOfMantissaBits).toInt.toRawUInt - &&& 0.toRawULong <= m &&& m <= (MantissaBitMask | MantissaExtraBit).toRawULong) +}//.ensuring((e, m) => (-DoubleBias - DoubleNoOfMantissaBits).toInt.toRawUInt <= e &&& e <= (DoubleBias - DoubleNoOfMantissaBits).toInt.toRawUInt + //&&& 0.toRawULong <= m &&& m <= (MantissaBitMask | MantissaExtraBit).toRawULong) def GetDoubleBitStringByMantissaAndExp(mantissa: ULong, exponentVal: Int): Long = { ((exponentVal + DoubleBias + DoubleNoOfMantissaBits) << DoubleNoOfMantissaBits) | (mantissa.toRaw & MantissaBitMask) diff --git a/asn1scala/src/main/scala/asn1scala/asn1jvm_Verification.scala b/asn1scala/src/main/scala/asn1scala/asn1jvm_Verification.scala index 7fc219c96..c4cf1c859 100644 --- a/asn1scala/src/main/scala/asn1scala/asn1jvm_Verification.scala +++ b/asn1scala/src/main/scala/asn1scala/asn1jvm_Verification.scala @@ -9,6 +9,7 @@ import stainless.math.* import StaticChecks.* @pure +@inlineOnce def arraySameElements[T](a1: Array[T], a2: Array[T]): Boolean = a1.length == a2.length && arrayRangesEqOffset(a1, a2, 0, a1.length, 0) @@ -32,14 +33,14 @@ def arrayCopyOffset[T](@pure src: Array[T], dst: Array[T], fromSrc: Int, toSrc: dst(fromDst) = src(fromSrc) arrayCopyOffset(src, dst, fromSrc + 1, toSrc, fromDst + 1) } -} +} ensuring ( _ => old(dst).length == dst.length) def arrayCopyOffsetLen[T](@pure src: Array[T], dst: Array[T], fromSrc: Int, fromDst: Int, len: Int): Unit = { require(0 <= len && len <= src.length && len <= dst.length) require(0 <= fromSrc && fromSrc <= src.length - len) require(0 <= fromDst && fromDst <= dst.length - len) arrayCopyOffset(src, dst, fromSrc, fromSrc + len, fromDst) -} +} ensuring ( _ => old(dst).length == dst.length) @pure def arrayBitIndices(fromBit: Long, toBit: Long): (Int, Int, Int, Int) = { @@ -51,16 +52,24 @@ def arrayBitIndices(fromBit: Long, toBit: Long): (Int, Int, Int, Int) = { (arrPrefixStart, arrPrefixEnd, fromBitIx, toBitIx) } -//def copyToArray[T](src: Array[T], dst: Array[T], startInDst: Int, len: Int): Unit = { -// require(0 <= len && len <= src.length) -// require(0 <= startInDst && startInDst <= src.length - len) -// require(src.length <= dst.length) -// arrayCopyOffset(src, dst, 0, len, startInDst) -//} - def byteRangesEq(b1: Byte, b2: Byte, from: Int, to: Int): Boolean = { - require(0 <= from && from <= to && to <= 7) - ((b1 & MASK_C(to) & MASK_B(8 - from)) & 0xFF) == ((b2 & MASK_C(to) & MASK_B(8 - from)) & 0xFF) + require(0 <= from && from <= to && to <= 8) + from == to || ((b1 & MASK_C(to) & MASK_B(8 - from)) & 0xFF) == ((b2 & MASK_C(to) & MASK_B(8 - from)) & 0xFF) +} + +// at = bit index, starting from MSB +def bitEqAt(b1: Byte, b2: Byte, at: Int): Boolean = { + require(0 <= at && at <= 7) + val mask = 1 << (7 - at) + (b1 & mask) == (b2 & mask) +} + +@pure +def bitAt(arr: Array[Byte], at: Long): Boolean = { + require(0 <= at && at < arr.length.toLong * 8) + val byteIx = (at / 8).toInt + val bitIx = (at % 8).toInt + (arr(byteIx) & BitAccessMasks(bitIx)) != 0 } @pure @@ -73,6 +82,38 @@ def arrayRangesEq[T](a1: Array[T], a2: Array[T], from: Int, to: Int): Boolean = else a1(from) == a2(from) && arrayRangesEq(a1, a2, from + 1, to) } +@pure @opaque @inlineOnce @ghost +def arrayRangesEqReflexiveLemma[T](a: Array[T]) = { + def rec(i: Int): Unit = { + require(0 <= i && i <= a.length) + require(arrayRangesEq(a, snapshot(a), i, a.length)) + decreases(i) + if (i == 0) () + else rec(i - 1) + }.ensuring(_ => arrayRangesEq(a, snapshot(a), 0, a.length)) + rec(a.length) +}.ensuring(_ => arrayRangesEq(a, snapshot(a), 0, a.length)) + +@pure @opaque @inlineOnce @ghost +def arrayRangesEqSymmetricLemma[T](a1: Array[T], a2: Array[T], from: Int, to: Int) = { + require(0 <= from && from <= to && to <= a1.length) + require(a1.length == a2.length) + require(arrayRangesEq(a1, a2, from, to)) + + def rec(i: Int): Unit = { + require(from <= i && i <= to) + require(arrayRangesEq(a2, a1, i, to)) + decreases(i) + if (i == from) () + else { + arrayRangesEqImpliesEq(a1, a2, from, i - 1, to) + rec(i - 1) + } + }.ensuring(_ => arrayRangesEq(a2, a1, from, to)) + + rec(to) +}.ensuring(_ => arrayRangesEq(a2, a1, from, to)) + @pure @opaque @inlineOnce @ghost def arrayUpdatedAtPrefixLemma[T](a: Array[T], at: Int, v: T): Unit = { require(0 <= at && at < a.length) @@ -194,7 +235,6 @@ def arrayRangesEqTransitive[T](a1: Array[T], a2: Array[T], a3: Array[T], from: I def arrayBitRangesEq(a1: Array[Byte], a2: Array[Byte], fromBit: Long, toBit: Long): Boolean = { require(a1.length <= a2.length) require(0 <= fromBit && fromBit <= toBit && toBit <= a1.length.toLong * 8) - require(fromBit < a1.length.toLong * 8) (fromBit < toBit) ==> { val (arrPrefixStart, arrPrefixEnd, fromBitIx, toBitIx) = arrayBitIndices(fromBit, toBit) val restFrom = (fromBit % 8).toInt @@ -203,21 +243,186 @@ def arrayBitRangesEq(a1: Array[Byte], a2: Array[Byte], fromBit: Long, toBit: Lon if (fromBitIx == toBitIx) { byteRangesEq(a1(fromBitIx), a2(fromBitIx), restFrom, restTo) } else { - byteRangesEq(a1(fromBitIx), a2(fromBitIx), restFrom, 7) && + byteRangesEq(a1(fromBitIx), a2(fromBitIx), restFrom, 8) && ((restTo != 0) ==> byteRangesEq(a1(toBitIx), a2(toBitIx), 0, restTo)) } } } } +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqReflexiveLemma(a: Array[Byte]) = { + def rec(i: Long): Unit = { + require(0 <= i && i <= a.length.toLong * 8L) + require(arrayBitRangesEq(a, snapshot(a), i, a.length * 8L)) + decreases(i) + if (i == 0) () + else rec(i - 1) + }.ensuring(_ => arrayBitRangesEq(a, snapshot(a), 0, a.length.toLong * 8L)) + rec(a.length.toLong * 8L) +}.ensuring(_ => arrayBitRangesEq(a, snapshot(a), 0, a.length.toLong * 8L)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqPrepend(a1: Array[Byte], a2: Array[Byte], from: Long, to: Long) = { + require(0 < from && from <= to) + require(a1.length == a2.length) + require(to <= a1.length.toLong * 8L) + require(arrayBitRangesEq(a1, a2, from, to)) + require(bitAt(a1, from - 1) == bitAt(a2, from - 1)) +}.ensuring(_ => arrayBitRangesEq(a1, a2, from - 1, to)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqDrop1(a1: Array[Byte], a2: Array[Byte], from: Long, to: Long) = { + require(0 <= from && from < to) + require(a1.length == a2.length) + require(to <= a1.length.toLong * 8L) + require(arrayBitRangesEq(a1, a2, from, to)) +}.ensuring(_ => arrayBitRangesEq(a1, a2, from + 1, to)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqAppend(a1: Array[Byte], a2: Array[Byte], from: Long, to: Long) = { + require(0 <= from && from <= to) + require(a1.length == a2.length) + require(to < a1.length.toLong * 8L) + require(arrayBitRangesEq(a1, a2, from, to)) + require(bitAt(a1, to) == bitAt(a2, to)) + + @opaque @inlineOnce + def rec(i: Long): Unit = { + require(from <= i && i <= to) + require(arrayBitRangesEq(a1, a2, i, to + 1)) + decreases(i) + if (i == from) () + else { + arrayBitRangesEqImpliesEq(a1, a2, from, i - 1, to) + arrayBitRangesEqPrepend(a1, a2, i, to + 1) + rec(i - 1) + } + }.ensuring { _ => + arrayBitRangesEq(a1, a2, from, to + 1) + } + + rec(to) +}.ensuring(_ => arrayBitRangesEq(a1, a2, from, to + 1)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesUpdatedAtLemma(a: Array[Byte], at: Long, b: Boolean): Unit = { + require(0 <= at && at < a.length.toLong * 8L) + + val byteIx = (at / 8).toInt + val bitIx = (at % 8).toInt + val newB = stainless.math.wrapping { ((a(byteIx) & ~BitAccessMasks(bitIx)) | (if (b) BitAccessMasks(bitIx) else 0)).toByte } + + { + @opaque @inlineOnce @ghost + def rec(i: Long): Unit = { + require(0 <= i && i <= at) + require(arrayBitRangesEq(a, snapshot(a).updated(byteIx, newB), i, at)) + decreases(i) + if (i == 0) () + else rec(i - 1) + }.ensuring { _ => + arrayBitRangesEq(a, snapshot(a).updated(byteIx, newB), 0, at) + } + + rec(at) + }.ensuring { _ => + arrayBitRangesEq(a, snapshot(a).updated(byteIx, newB), 0, at) + } +} + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqTransitive(a1: Array[Byte], a2: Array[Byte], a3: Array[Byte], from: Long, mid: Long, to: Long): Unit = { + require(0 <= from && from <= mid && mid <= to) + require(a1.length == a2.length && a2.length == a3.length) + require(mid <= a1.length.toLong * 8L && to <= a2.length.toLong * 8L) + require(arrayBitRangesEq(a1, a2, from, mid)) + require(arrayBitRangesEq(a2, a3, from, to)) + + @opaque @inlineOnce @ghost + def rec(i: Long): Unit = { + require(from <= i && i <= mid) + require(arrayBitRangesEq(a1, a2, i, mid)) + require(arrayBitRangesEq(a2, a3, i, to)) + require(arrayBitRangesEq(a1, a3, from, i)) + decreases(to - i) + if (i == mid) () + else { + arrayBitRangesEqAppend(a1, a3, from, i) + arrayBitRangesEqDrop1(a1, a2, i, mid) + arrayBitRangesEqDrop1(a2, a3, i, to) + rec(i + 1) + } + }.ensuring { _ => + arrayBitRangesEq(a1, a3, from, mid) + } + rec(from) +}.ensuring(_ => arrayBitRangesEq(a1, a3, from, mid)) + + +@ghost @pure @opaque @inlineOnce +def arrayBitEqImpliesRangesEqLemma(a: Array[Byte]): Unit = { + @ghost @pure @opaque @inlineOnce + def rec(i: Long): Unit = { + require(0 <= i && i <= a.length.toLong * 8) + require(arrayBitRangesEq(a, snapshot(a), i, a.length.toLong * 8)) + decreases(i) + if (i == 0) () + else rec(i - 1) + }.ensuring(_ => arrayBitRangesEq(a, snapshot(a), 0, a.length.toLong * 8)) + rec(a.length.toLong * 8) +}.ensuring(_ => arrayBitRangesEq(a, snapshot(a), 0, a.length.toLong * 8)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqImpliesEq(a1: Array[Byte], a2: Array[Byte], from: Long, at: Long, to: Long): Unit = { + require(0 <= from && from <= to) + require(a1.length == a2.length) + require(to <= a1.length.toLong * 8) + require(from <= at && at < to) + require(arrayBitRangesEq(a1, a2, from, to)) + + @pure @opaque @inlineOnce @ghost + def rec(i: Long): Unit = { + require(from <= i && i <= at) + require(arrayBitRangesEq(a1, a2, i, to)) + decreases(to - i) + if (i == at) () + else rec(i + 1) + }.ensuring { _ => + bitAt(a1, at) == bitAt(a2, at) + } + rec(from) +}.ensuring(_ => bitAt(a1, at) == bitAt(a2, at)) + +@pure @opaque @inlineOnce @ghost +def arrayBitRangesEqImpliesBitEq(a1: Array[Byte], a2: Array[Byte], from: Long, atByte: Int, to: Long): Unit = { + require(0 <= from && from <= to) + require(a1.length == a2.length) + require(to <= a1.length.toLong * 8) + require((from + 7) / 8 <= atByte && atByte < to / 8) + require(arrayBitRangesEq(a1, a2, from, to)) + + @pure @opaque @inlineOnce @ghost + def rec(i: Long): Unit = { + require((from + 7) / 8 <= i && i <= atByte.toLong * 8L) + require(arrayBitRangesEq(a1, a2, i, to)) + decreases(to - i) + if (i / 8 == atByte) () + else rec(i + 1) + }.ensuring { _ => + a1(atByte) == a2(atByte) + } + rec(from) +}.ensuring(_ => a1(atByte) == a2(atByte)) + @ghost @pure @opaque @inlineOnce def arrayBitRangesEqSlicedLemma(a1: Array[Byte], a2: Array[Byte], fromBit: Long, toBit: Long, fromSlice: Long, toSlice: Long): Unit = { require(a1.length <= a2.length) require(0 <= fromBit && fromBit <= toBit && toBit <= a1.length.toLong * 8) - require(fromBit < a1.length.toLong * 8) + require(fromBit <= a1.length.toLong * 8) require(arrayBitRangesEq(a1, a2, fromBit, toBit)) require(fromBit <= fromSlice && fromSlice <= toSlice && toSlice <= toBit) - require(fromSlice < a1.length.toLong * 8) + require(fromSlice <= a1.length.toLong * 8) if (fromSlice == toSlice) () else { diff --git a/asn1scala/stainless.conf b/asn1scala/stainless.conf new file mode 100644 index 000000000..ccd846260 --- /dev/null +++ b/asn1scala/stainless.conf @@ -0,0 +1,16 @@ +# The settings below correspond to the various +# options listed by `stainless --help` + +vc-cache = true +# debug = ["verification", "smt"] +timeout = 220 +check-models = false +print-ids = false +print-types = false +batched = true +strict-arithmetic = true +solvers = "smt-cvc5,smt-z3,smt-cvc4" +check-measures = yes +infer-measures = true +simplifier = "ol" +# no-colors = false \ No newline at end of file diff --git a/asn1scala/verify.sh b/asn1scala/verify.sh new file mode 100755 index 000000000..d6cf93104 --- /dev/null +++ b/asn1scala/verify.sh @@ -0,0 +1,80 @@ +stainless-dotty src/main/scala/asn1scala/asn1jvm.scala \ +src/main/scala/asn1scala/asn1jvm_Verification.scala \ +src/main/scala/asn1scala/asn1jvm_Helper.scala \ +src/main/scala/asn1scala/asn1jvm_Bitstream.scala \ +src/main/scala/asn1scala/asn1jvm_Codec.scala \ +src/main/scala/asn1scala/asn1jvm_Codec_ACN.scala \ +--config-file=stainless.conf \ +-D-parallel=12 \ +--watch \ +--functions=\ +enc_IA5String_CharIndex_External_Field_Determinant,\ +dec_IA5String_CharIndex_External_Field_Determinant,\ +dec_Int_TwosComplement_ConstSize_little_endian_64,\ +dec_Real_IEEE754_32_big_endian,\ +dec_Real_IEEE754_32_little_endian,\ +dec_Real_IEEE754_64_big_endian,\ +dec_Real_IEEE754_64_little_endian,\ +milbus_encode,\ +milbus_decode\ +BitStream_ReadBitPattern,\ +dec_IA5String_CharIndex_Internal_Field_Determinant,\ +dec_String_CharIndex_private,\ +enc_String_CharIndex_private,\ +GetCharIndex,\ +initACNCodec,\ +reader,\ +readPrefixLemma_TODO,\ +dec_Int_PositiveInteger_ConstSize_big_endian_16_prefixLemma,\ +dec_Int_PositiveInteger_ConstSize_big_endian_32_prefixLemma,\ +dec_Int_PositiveInteger_ConstSize_big_endian_64_prefixLemma,\ +dec_Int_PositiveInteger_ConstSize_little_endian_16_prefixLemma,\ +dec_Int_PositiveInteger_ConstSize_little_endian_32_prefixLemma,\ +dec_Int_PositiveInteger_ConstSize_little_endian_64_prefixLemma,\ +enc_Int_PositiveInteger_ConstSize,\ +enc_Int_PositiveInteger_ConstSize,\ +resetAt,\ +withMovedByteIndex,\ +withMovedBitIndex,\ +isPrefixOf,\ +enc_Int_PositiveInteger_ConstSize_8,\ +enc_Int_PositiveInteger_ConstSize_big_endian_16,\ +enc_Int_PositiveInteger_ConstSize_big_endian_32,\ +enc_Int_PositiveInteger_ConstSize_big_endian_64,\ +dec_Int_PositiveInteger_ConstSize,\ +dec_Int_PositiveInteger_ConstSize_pure,\ +dec_Int_PositiveInteger_ConstSize_8,\ +dec_Int_PositiveInteger_ConstSize_big_endian_16,\ +dec_Int_PositiveInteger_ConstSize_big_endian_16_pure,\ +dec_Int_PositiveInteger_ConstSize_big_endian_32,\ +dec_Int_PositiveInteger_ConstSize_big_endian_32_pure,\ +dec_Int_PositiveInteger_ConstSize_big_endian_64,\ +dec_Int_PositiveInteger_ConstSize_big_endian_64_pure,\ +dec_Int_PositiveInteger_ConstSize_little_endian_16_pure,\ +dec_Int_PositiveInteger_ConstSize_little_endian_32_pure,\ +dec_Int_PositiveInteger_ConstSize_little_endian_64_pure,\ +enc_Int_TwosComplement_ConstSize,\ +enc_Int_TwosComplement_ConstSize_8,\ +enc_Int_TwosComplement_ConstSize_big_endian_16,\ +enc_Int_TwosComplement_ConstSize_big_endian_32,\ +enc_Int_TwosComplement_ConstSize_big_endian_64,\ +dec_Int_TwosComplement_ConstSize,\ +dec_Int_TwosComplement_ConstSize_pure,\ +dec_Int_TwosComplement_ConstSize_8,\ +dec_Int_TwosComplement_ConstSize_big_endian_16,\ +dec_Int_TwosComplement_ConstSize_big_endian_32,\ +dec_Int_TwosComplement_ConstSize_big_endian_64,\ +enc_Real_IEEE754_32_big_endian,\ +enc_Real_IEEE754_32_little_endian,\ +enc_Real_IEEE754_64_big_endian,\ +enc_Real_IEEE754_64_little_endian,\ +dec_Int_TwosComplement_ConstSize_little_endian_16,\ +dec_Int_TwosComplement_ConstSize_little_endian_32,\ +dec_Int_TwosComplement_ConstSize_little_endian_64,\ +dec_Real_IEEE754_32_big_endian,\ +dec_Real_IEEE754_32_little_endian,\ +dec_Real_IEEE754_64_big_endian,\ +dec_Real_IEEE754_64_little_endian,\ +milbus_encode,\ +milbus_decode\ +$1 \ No newline at end of file diff --git a/asn1scala/verify_without_codec.sh b/asn1scala/verify_without_codec.sh new file mode 100755 index 000000000..e687e937b --- /dev/null +++ b/asn1scala/verify_without_codec.sh @@ -0,0 +1,8 @@ +stainless-dotty src/main/scala/asn1scala/asn1jvm.scala \ +src/main/scala/asn1scala/asn1jvm_Verification.scala \ +src/main/scala/asn1scala/asn1jvm_Helper.scala \ +src/main/scala/asn1scala/asn1jvm_Bitstream.scala \ +--config-file=stainless.conf \ +-D-parallel=8 \ +--watch \ +$1 \ No newline at end of file