diff --git a/implement/Pine.Core/ElmInteractive/ElmValue.cs b/implement/Pine.Core/ElmInteractive/ElmValue.cs index 2ca33a31..910f6a8b 100644 --- a/implement/Pine.Core/ElmInteractive/ElmValue.cs +++ b/implement/Pine.Core/ElmInteractive/ElmValue.cs @@ -21,6 +21,7 @@ type ElmValue | ElmString String | ElmTag String (List ElmValue) | ElmRecord (List ( String, ElmValue )) + | ElmBytes Bytes | ElmFloat BigInt.BigInt BigInt.BigInt | ElmInternal String @@ -37,6 +38,8 @@ override public string ToString() => public const string ElmRecordTypeTagName = "Elm_Record"; + public const string ElmBytesTypeTagName = "Elm_Bytes"; + public const string ElmStringTypeTagName = "String"; public const string ElmSetTypeTagName = "Set_elm_builtin"; @@ -50,6 +53,9 @@ override public string ToString() => public static readonly PineValue ElmRecordTypeTagNameAsValue = PineValueAsString.ValueFromString(ElmRecordTypeTagName); + public static readonly PineValue ElmBytesTypeTagNameAsValue = + PineValueAsString.ValueFromString(ElmBytesTypeTagName); + public static readonly PineValue ElmStringTypeTagNameAsValue = PineValueAsString.ValueFromString(ElmStringTypeTagName); @@ -364,6 +370,35 @@ public override string ToString() => Fields.FirstOrDefault(field => field.FieldName == fieldName).Value; } + /// + /// Elm Bytes type from https://package.elm-lang.org/packages/elm/bytes/latest/ + /// + public record ElmBytes(ReadOnlyMemory Value) + : ElmValue + { + /// + /// The number of contained nodes is always zero for the 'Bytes' variant. + /// + public override int ContainedNodesCount { get; } = 0; + + + /// + public virtual bool Equals(ElmBytes? otherBytes) + { + if (otherBytes is null) + return false; + + if (Value.Length != otherBytes.Value.Length) + return false; + + return Value.Span.SequenceEqual(otherBytes.Value.Span); + } + + /// + public override int GetHashCode() => + Value.GetHashCode(); + } + /// /// The Elm compiler included with Pine models the 'Float' type from Elm as a rational number, /// expressed as the quotient or fraction โ of two integers, a numerator and a denominator. @@ -503,6 +538,9 @@ public static (string expressionString, bool needsParens) RenderAsElmExpression( ElmTag tag => ElmTagAsExpression(tag.TagName, tag.Arguments), + ElmBytes bytes => + ("<" + bytes.Value.Length + " bytes>", needsParens: false), + ElmFloat elmFloat => (Convert.ToString( (double)elmFloat.Numerator / (double)elmFloat.Denominator, diff --git a/implement/Pine.Core/ElmInteractive/ElmValueEncoding.cs b/implement/Pine.Core/ElmInteractive/ElmValueEncoding.cs index 32755aa6..1add5dad 100644 --- a/implement/Pine.Core/ElmInteractive/ElmValueEncoding.cs +++ b/implement/Pine.Core/ElmInteractive/ElmValueEncoding.cs @@ -143,6 +143,26 @@ public static Result PineListValueAsElmValue(PineValue.ListVal } } + { + // case of Bytes.Bytes + + if (listValue.Elements[0] == ElmValue.ElmBytesTypeTagNameAsValue) + { + var tagArgumentsValue = listValue.Elements[1]; + + if (tagArgumentsValue is not PineValue.ListValue tagArgumentsList) + return "Failed to convert value under Bytes tag: Expected a list of tag arguments"; + + if (tagArgumentsList.Elements.Count is not 1) + return "Failed to convert value under Bytes tag: Expected a list of tag arguments with single item"; + + if (tagArgumentsList.Elements[0] is not PineValue.BlobValue blobValue) + return "Failed to convert value under Bytes tag: Expected blob value in tag argument"; + + return new ElmValue.ElmBytes(blobValue.Bytes); + } + } + { // Optimize for the case of an Elm Float. @@ -332,6 +352,7 @@ public static Result PineListValueAsElmValue(PineValue.ListVal recordFields[i] = (fieldName.Value, fieldValueOk.Value); continue; } + return "Failed decoding field value: " + fieldValueResult; } @@ -450,6 +471,11 @@ [.. elmList.Elements.Select(item => ElmValueAsPineValue(item, reusableEncoding)) ElmRecordAsPineValue( [.. elmRecord.Fields.Select(field => (field.FieldName, ElmValueAsPineValue(field.Value, reusableEncoding)))]), + ElmValue.ElmBytes elmBytes => + PineValue.List( + [ElmValue.ElmBytesTypeTagNameAsValue, + PineValue.List([PineValue.Blob(elmBytes.Value)])]), + ElmValue.ElmFloat elmFloat => PineValue.List( [ElmValue.ElmFloatTypeTagNameAsValue, diff --git a/implement/Pine.Core/PopularValues.cs b/implement/Pine.Core/PopularValues.cs index 6b09cf59..586fbc6b 100644 --- a/implement/Pine.Core/PopularValues.cs +++ b/implement/Pine.Core/PopularValues.cs @@ -24,6 +24,7 @@ from c2 in Enumerable.Range(0, 128) private static IEnumerable PopularStringsSource => [ "Elm_Record", + "Elm_Bytes", "Basics", "List", diff --git a/implement/pine/ElmTime/compile-elm-program/src/ElmCompiler.elm b/implement/pine/ElmTime/compile-elm-program/src/ElmCompiler.elm index 31f23860..4f6c70c1 100644 --- a/implement/pine/ElmTime/compile-elm-program/src/ElmCompiler.elm +++ b/implement/pine/ElmTime/compile-elm-program/src/ElmCompiler.elm @@ -9,6 +9,7 @@ module ElmCompiler exposing , compilationAndEmitStackFromModulesInCompilation , compileElmSyntaxExpression , compileElmSyntaxFunction + , elmBytesTypeTagNameAsValue , elmFloatTypeTagName , elmRecordTypeTagName , elmRecordTypeTagNameAsValue @@ -142,6 +143,16 @@ elmRecordTypeTagNameAsValue = Pine.valueFromString elmRecordTypeTagName +elmBytesTypeTagName : String +elmBytesTypeTagName = + "Elm_Bytes" + + +elmBytesTypeTagNameAsValue : Pine.Value +elmBytesTypeTagNameAsValue = + Pine.valueFromString elmBytesTypeTagName + + elmFloatTypeTagName : String elmFloatTypeTagName = "Elm_Float" diff --git a/implement/pine/ElmTime/compile-elm-program/src/ElmInteractive.elm b/implement/pine/ElmTime/compile-elm-program/src/ElmInteractive.elm index 9cd54c88..fe66b931 100644 --- a/implement/pine/ElmTime/compile-elm-program/src/ElmInteractive.elm +++ b/implement/pine/ElmTime/compile-elm-program/src/ElmInteractive.elm @@ -13,6 +13,7 @@ import ElmCompiler , ElmModuleInCompilation , ProjectParsedElmFile , compilationAndEmitStackFromModulesInCompilation + , elmBytesTypeTagNameAsValue , elmFloatTypeTagName , elmRecordTypeTagName , elmStringTypeTagName @@ -58,6 +59,7 @@ type ElmValue | ElmString String | ElmTag String (List ElmValue) | ElmRecord (List ( String, ElmValue )) + | ElmBytes (List Int) | ElmFloat BigInt.BigInt BigInt.BigInt | ElmInternal String @@ -185,6 +187,11 @@ renderAsElmExpression elmValue = , { needsParens = True } ) + ElmBytes blob -> + ( "<" ++ String.fromInt (List.length blob) ++ " bytes>" + , { needsParens = False } + ) + ElmFloat numerator denominator -> ( case elmFloatToFloat numerator denominator of Nothing -> @@ -219,10 +226,24 @@ elmValueAsJson elmValue = Json.Encode.list elmValueAsJson list ElmRecord fields -> - Json.Encode.list (\( fieldName, fieldValue ) -> Json.Encode.list identity [ Json.Encode.string fieldName, elmValueAsJson fieldValue ]) fields + Json.Encode.list + (\( fieldName, fieldValue ) -> + Json.Encode.list identity [ Json.Encode.string fieldName, elmValueAsJson fieldValue ] + ) + fields ElmTag tagName tagArguments -> - Json.Encode.list identity [ Json.Encode.string tagName, Json.Encode.list elmValueAsJson tagArguments ] + Json.Encode.list identity + [ Json.Encode.string tagName + , Json.Encode.list elmValueAsJson tagArguments + ] + + ElmBytes blob -> + Json.Encode.object + [ ( "Elm_Bytes" + , Json.Encode.list Json.Encode.int blob + ) + ] ElmFloat numerator denominator -> case elmFloatToFloat numerator denominator of @@ -291,70 +312,88 @@ pineValueAsElmValue pineValue = |> Ok Pine.ListValue list -> - case list |> List.map pineValueAsElmValue |> Result.Extra.combine of - Err error -> - Err ("Failed to combine list: " ++ error) + let + genericList () = + case list |> List.map pineValueAsElmValue |> Result.Extra.combine of + Err error -> + Err ("Failed to combine list: " ++ error) - Ok listValues -> - let - resultAsList = - Ok (ElmList listValues) - in - if listValues == [] then - resultAsList - - else - case listValues of - [ ElmList tagNameChars, ElmList tagArguments ] -> - case tryMapElmValueToString tagNameChars of - Just tagName -> - if stringStartsWithUpper tagName then - if tagName == elmRecordTypeTagName then - (case tagArguments of - [ recordValue ] -> - elmValueAsElmRecord recordValue - - _ -> - Err ("Wrong number of tag arguments: " ++ String.fromInt (List.length tagArguments)) - ) - |> Result.mapError ((++) "Failed to extract value under record tag: ") - - else if tagName == elmStringTypeTagName then - (case tagArguments of - [ ElmList charsList ] -> - charsList - |> tryMapElmValueToString - |> Maybe.map (ElmString >> Ok) - |> Maybe.withDefault (Err "Failed to map chars") - - _ -> - Err - ("Unexpected shape of tag arguments (" - ++ String.fromInt (List.length tagArguments) - ++ "): " - ) - ) - |> Result.mapError ((++) "Failed to extract value under String tag: ") - - else if tagName == elmFloatTypeTagName then - case tagArguments of - [ ElmInteger numerator, ElmInteger denominator ] -> - Ok (ElmFloat numerator denominator) - - _ -> - Err "Unexpected shape under Float tag" - - else - Ok (ElmTag tagName tagArguments) - - else - resultAsList + Ok listValues -> + let + resultAsList = + Ok (ElmList listValues) + in + if listValues == [] then + resultAsList - Nothing -> + else + case listValues of + [ ElmList tagNameChars, ElmList tagArguments ] -> + case tryMapElmValueToString tagNameChars of + Just tagName -> + if stringStartsWithUpper tagName then + if tagName == elmRecordTypeTagName then + (case tagArguments of + [ recordValue ] -> + elmValueAsElmRecord recordValue + + _ -> + Err ("Wrong number of tag arguments: " ++ String.fromInt (List.length tagArguments)) + ) + |> Result.mapError ((++) "Failed to extract value under record tag: ") + + else if tagName == elmStringTypeTagName then + (case tagArguments of + [ ElmList charsList ] -> + charsList + |> tryMapElmValueToString + |> Maybe.map (ElmString >> Ok) + |> Maybe.withDefault (Err "Failed to map chars") + + _ -> + Err + ("Unexpected shape of tag arguments (" + ++ String.fromInt (List.length tagArguments) + ++ "): " + ) + ) + |> Result.mapError ((++) "Failed to extract value under String tag: ") + + else if tagName == elmFloatTypeTagName then + case tagArguments of + [ ElmInteger numerator, ElmInteger denominator ] -> + Ok (ElmFloat numerator denominator) + + _ -> + Err "Unexpected shape under Float tag" + + else + Ok (ElmTag tagName tagArguments) + + else + resultAsList + + Nothing -> + resultAsList + + _ -> resultAsList + in + case list of + [ tagValue, Pine.ListValue tagArguments ] -> + if tagValue == elmBytesTypeTagNameAsValue then + case tagArguments of + [ Pine.BlobValue blob ] -> + Ok (ElmBytes blob) _ -> - resultAsList + genericList () + + else + genericList () + + _ -> + genericList () elmValueAsElmRecord : ElmValue -> Result String ElmValue @@ -613,13 +652,13 @@ json_encode_pineValue dictionary value = (\entryName entryValue aggregate -> case entryValue of Pine.BlobValue blob -> - if List.length blob < 3 then - aggregate + if List.length blob < 3 then + aggregate - else - { aggregate - | blobDict = Dict.insert blob entryName aggregate.blobDict - } + else + { aggregate + | blobDict = Dict.insert blob entryName aggregate.blobDict + } Pine.ListValue list -> if list == [] then @@ -726,78 +765,78 @@ json_encode_pineValue_Internal dictionary value = jsonEncodeEmptyBlob _ -> - if List.length blob < 3 then - case intFromBlobValueStrict blob of - Err _ -> - defaultBlobEncoding () + if List.length blob < 3 then + case intFromBlobValueStrict blob of + Err _ -> + defaultBlobEncoding () - Ok asInt -> - Json.Encode.object - [ ( "BlobAsInt" - , Json.Encode.int asInt - ) - ] + Ok asInt -> + Json.Encode.object + [ ( "BlobAsInt" + , Json.Encode.int asInt + ) + ] - else - tryFindReference () + else + tryFindReference () intFromBlobValueStrict : List Int -> Result String Int intFromBlobValueStrict blobBytes = - case blobBytes of - [] -> - Err "Empty blob does not encode an integer." + case blobBytes of + [] -> + Err "Empty blob does not encode an integer." - [ _ ] -> - Err "Blob with only one byte does not encode an integer." + [ _ ] -> + Err "Blob with only one byte does not encode an integer." - sign :: absFirst :: following -> - let - computeAbsValue () = - if following == [] then - Ok absFirst + sign :: absFirst :: following -> + let + computeAbsValue () = + if following == [] then + Ok absFirst - else if absFirst == 0 then - Err "Avoid ambiguous leading zero." + else if absFirst == 0 then + Err "Avoid ambiguous leading zero." - else - case following of - [ b1 ] -> - Ok ((absFirst * 256) + b1) + else + case following of + [ b1 ] -> + Ok ((absFirst * 256) + b1) - [ b1, b2 ] -> - Ok ((absFirst * 65536) + (b1 * 256) + b2) + [ b1, b2 ] -> + Ok ((absFirst * 65536) + (b1 * 256) + b2) - [ b1, b2, b3 ] -> - Ok ((absFirst * 16777216) + (b1 * 65536) + (b2 * 256) + b3) + [ b1, b2, b3 ] -> + Ok ((absFirst * 16777216) + (b1 * 65536) + (b2 * 256) + b3) - [ b1, b2, b3, b4 ] -> - Ok ((absFirst * 4294967296) + (b1 * 16777216) + (b2 * 65536) + (b3 * 256) + b4) + [ b1, b2, b3, b4 ] -> + Ok ((absFirst * 4294967296) + (b1 * 16777216) + (b2 * 65536) + (b3 * 256) + b4) - [ b1, b2, b3, b4, b5 ] -> - Ok ((absFirst * 1099511627776) + (b1 * 4294967296) + (b2 * 16777216) + (b3 * 65536) + (b4 * 256) + b5) + [ b1, b2, b3, b4, b5 ] -> + Ok ((absFirst * 1099511627776) + (b1 * 4294967296) + (b2 * 16777216) + (b3 * 65536) + (b4 * 256) + b5) - _ -> - Err "Failed to map to int - unsupported number of bytes" - in - case sign of - 4 -> - computeAbsValue () + _ -> + Err "Failed to map to int - unsupported number of bytes" + in + case sign of + 4 -> + computeAbsValue () - 2 -> - case computeAbsValue () of - Err err -> - Err err + 2 -> + case computeAbsValue () of + Err err -> + Err err - Ok absValue -> - if absValue == 0 then - Err "Avoid ambiguous negative zero." + Ok absValue -> + if absValue == 0 then + Err "Avoid ambiguous negative zero." - else - Ok -absValue + else + Ok -absValue - _ -> - Err ("Unexpected value for sign byte: " ++ String.fromInt sign) + _ -> + Err ("Unexpected value for sign byte: " ++ String.fromInt sign) jsonEncodeEmptyList : Json.Encode.Value diff --git a/implement/pine/ElmTime/compile-elm-program/src/ElmInteractiveKernelModules.elm b/implement/pine/ElmTime/compile-elm-program/src/ElmInteractiveKernelModules.elm index c98df94f..04a37932 100644 --- a/implement/pine/ElmTime/compile-elm-program/src/ElmInteractiveKernelModules.elm +++ b/implement/pine/ElmTime/compile-elm-program/src/ElmInteractiveKernelModules.elm @@ -8,16 +8,19 @@ module Bytes exposing (..) type Bytes - = Bytes (List Int) + = Elm_Bytes Int width : Bytes -> Int width bytes = case bytes of - Bytes list -> Pine_kernel.length list + Elm_Bytes list -> + Pine_kernel.length list -type Endianness = LE | BE +type Endianness + = LE + | BE """ , """ @@ -37,10 +40,10 @@ type Encoder encode : Encoder -> Bytes.Bytes encode builder = - Bytes.Bytes (encodeBlob builder) + Bytes.Elm_Bytes (encodeBlob builder) -encodeBlob : Encoder -> List Int +encodeBlob : Encoder -> Int encodeBlob builder = case builder of U8 n -> @@ -61,15 +64,20 @@ encodeBlob builder = Pine_kernel.take [ 4, (Pine_kernel.reverse (Pine_kernel.skip [ 1, n ])) ] in if (e == Bytes.LE) - then littleEndian - else Pine_kernel.reverse littleEndian + then + littleEndian + else + Pine_kernel.reverse littleEndian SequenceEncoder bs -> - Pine_kernel.concat (List.map encodeBlob bs) + if bs == [] + then + Pine_kernel.take [ 0, 0 ] + else + Pine_kernel.concat (List.map encodeBlob bs) - BytesEncoder bs -> - case bs of - Bytes.Bytes blob -> blob + BytesEncoder (Bytes.Elm_Bytes blob) -> + blob -- INTEGERS @@ -78,8 +86,8 @@ encodeBlob builder = {-| Encode integers from `0` to `255` in one byte. -} unsignedInt8 : Int -> Encoder -unsignedInt8 = - U8 +unsignedInt8 int = + U8 int {-| Encode integers from `0` to `65535` in two bytes. @@ -97,13 +105,221 @@ unsignedInt32 = bytes : Bytes.Bytes -> Encoder -bytes = - Bytes.Bytes +bytes bytes = + BytesEncoder bytes sequence : List Encoder -> Encoder sequence builders = - SequenceEncoder builders + SequenceEncoder builders + + +string : String -> Encoder +string (String chars)= + let + blob = + encodeCharsAsBlob chars + in + BytesEncoder (Bytes.Elm_Bytes blob) + + +encodeCharsAsBlob : List Char -> Int +encodeCharsAsBlob chars = + encodeCharsAsBlobRec + (Pine_kernel.take [ 0, 0 ]) + chars + + +encodeCharsAsBlobRec : Int -> List Char -> Int +encodeCharsAsBlobRec prefix chars = + case chars of + [] -> + prefix + + char :: rest -> + let + code = + Char.toCode char + + charUtf8 = + if Pine_kernel.is_sorted_ascending_int [ code, 0x7f ] then + -- 1-byte encoding + char + + else if Pine_kernel.is_sorted_ascending_int [ code, 0x7ff ] then + -- 2-byte encoding + let + byte1 = + 0xC0 + (code // 64) + + byte2 = + 0x80 + modBy 64 code + in + Pine_kernel.concat + [ Pine_kernel.take [ 1, Pine_kernel.reverse byte1 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte2 ] + ] + + else if Pine_kernel.is_sorted_ascending_int [ code, 0xffff ] then + -- 3-byte encoding + let + byte1 = + 0xE0 + (code // 4096) + + byte2 = + 0x80 + modBy 64 (code // 64) + + byte3 = + 0x80 + modBy 64 code + in + Pine_kernel.concat + [ Pine_kernel.take [ 1, Pine_kernel.reverse byte1 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte2 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte3 ] + ] + + else + -- 4-byte encoding for code points >= 0x10000 + let + byte1 = + 0xF0 + (code // 262144) + + byte2 = + 0x80 + modBy 64 (code // 4096) + + byte3 = + 0x80 + modBy 64 (code // 64) + + byte4 = + 0x80 + modBy 64 code + in + Pine_kernel.concat + [ Pine_kernel.take [ 1, Pine_kernel.reverse byte1 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte2 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte3 ] + , Pine_kernel.take [ 1, Pine_kernel.reverse byte4 ] + ] + in + encodeCharsAsBlobRec + (Pine_kernel.concat [ prefix, charUtf8 ]) + rest + + +getStringWidth : String -> Int +getStringWidth (String chars) = + Pine_kernel.length + (encodeCharsAsBlob chars) + + +""" + , """ +module Bytes.Decode exposing (..) + + +import Bytes + + +-- PARSER + + +{-| Describes how to turn a sequence of bytes into a nice Elm value. +-} +type Decoder a + = Decoder (Bytes -> Int -> ( Int, a )) + + +{-| Turn a sequence of bytes into a nice Elm value. + + -- decode (unsignedInt16 BE) <0007> == Just 7 + -- decode (unsignedInt16 LE) <0700> == Just 7 + -- decode (unsignedInt16 BE) <0700> == Just 1792 + -- decode (unsignedInt32 BE) <0700> == Nothing + + + +The `Decoder` specifies exactly how this should happen. This process may fail +if the sequence of bytes is corrupted or unexpected somehow. The examples above +show a case where there are not enough bytes. + +-} +decode : Decoder a -> Bytes -> Maybe a +decode (Decoder decoder) bytes = + let + (Bytes.Elm_Bytes blob) = + bytes + + ( offset, result ) = + decoder bytes 0 + + blobLength = + Pine_kernel.length blob + in + if Pine_kernel.is_sorted_ascending_int [ 0, offset, blobLength ] + then + Just result + else + Nothing + + +{-| Decode one byte into an integer from `0` to `255`. +-} +unsignedInt8 : Decoder Int +unsignedInt8 = + Decoder + (\\(Bytes.Elm_Bytes blob) offset -> + let + byte = + Pine_kernel.take [ 1, Pine_kernel.skip [ offset, blob ] ] + in + ( Pine_kernel.add_int [ offset, 1 ] + , Pine_kernel.concat [ Pine_kernel.take [ 1, 0 ], byte ] + ) + ) + + +succeed : a -> Decoder a +succeed a = + Decoder (\\_ offset -> ( offset, a )) + + +map : (a -> b) -> Decoder a -> Decoder b +map func (Decoder decodeA) = + Decoder + (\\bites offset -> + let + ( aOffset, a ) = + decodeA bites offset + in + ( aOffset, func a ) + ) + + +type Step state a + = Loop state + | Done a + + +loop : state -> (state -> Decoder (Step state a)) -> Decoder a +loop state callback = + Decoder (loopHelp state callback) + + +loopHelp : state -> (state -> Decoder (Step state a)) -> Bytes -> Int -> ( Int, a ) +loopHelp state callback bites offset = + let + (Decoder decoder) = + callback state + + ( newOffset, step ) = + decoder bites offset + in + case step of + Loop newState -> + loopHelp newState callback bites newOffset + + Done result -> + ( newOffset, result ) + """ , """ diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/.gitignore b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/.gitignore new file mode 100644 index 00000000..aee98106 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/.gitignore @@ -0,0 +1 @@ +/elm-stuff/ diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/elm.json b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/elm.json new file mode 100644 index 00000000..c175df83 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/elm.json @@ -0,0 +1,18 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/bytes": "1.0.8", + "elm/core": "1.0.5" + }, + "indirect": {} + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/src/DecodeExtra.elm b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/src/DecodeExtra.elm new file mode 100644 index 00000000..81012dc3 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/context-app/src/DecodeExtra.elm @@ -0,0 +1,25 @@ +module DecodeExtra exposing (..) + +import Bytes.Decode + + +list : Int -> Bytes.Decode.Decoder a -> Bytes.Decode.Decoder (List a) +list length aDecoder = + Bytes.Decode.loop + ( length, [] ) + (listStep aDecoder) + + +listStep : + Bytes.Decode.Decoder a + -> ( Int, List a ) + -> Bytes.Decode.Decoder (Bytes.Decode.Step ( Int, List a ) (List a)) +listStep elementDecoder ( n, elements ) = + if n <= 0 then + Bytes.Decode.succeed + (Bytes.Decode.Done (List.reverse elements)) + + else + Bytes.Decode.map + (\element -> Bytes.Decode.Loop ( n - 1, element :: elements )) + elementDecoder diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/expected-value.txt new file mode 100644 index 00000000..4020c25f --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/expected-value.txt @@ -0,0 +1 @@ +<1 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/submission.txt new file mode 100644 index 00000000..d884ef68 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/110/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.unsignedInt8 17) \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/expected-value.txt new file mode 100644 index 00000000..29bdeeba --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/expected-value.txt @@ -0,0 +1 @@ +<0 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/submission.txt new file mode 100644 index 00000000..d490adc4 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/210/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.sequence []) \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/expected-value.txt new file mode 100644 index 00000000..4020c25f --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/expected-value.txt @@ -0,0 +1 @@ +<1 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/submission.txt new file mode 100644 index 00000000..2167159a --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/211/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.sequence [ Bytes.Encode.unsignedInt8 17 ]) \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/expected-value.txt new file mode 100644 index 00000000..498204f1 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/expected-value.txt @@ -0,0 +1 @@ +<2 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/submission.txt new file mode 100644 index 00000000..878d4182 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/212/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.sequence [ Bytes.Encode.unsignedInt8 0, Bytes.Encode.unsignedInt8 17 ]) \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/expected-value.txt new file mode 100644 index 00000000..29bdeeba --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/expected-value.txt @@ -0,0 +1 @@ +<0 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/submission.txt new file mode 100644 index 00000000..12f5bd36 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/310/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.string "") \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/expected-value.txt new file mode 100644 index 00000000..4a0eaef0 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/expected-value.txt @@ -0,0 +1 @@ +<11 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/submission.txt new file mode 100644 index 00000000..daa4ba2d --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/311/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.string "Hello World") \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/expected-value.txt new file mode 100644 index 00000000..c10e6afe --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/expected-value.txt @@ -0,0 +1 @@ +<4 bytes> \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/submission.txt new file mode 100644 index 00000000..695ccc00 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/334/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.encode (Bytes.Encode.string "๐ŸŒฒ") \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/expected-value.txt new file mode 100644 index 00000000..c2270834 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/expected-value.txt @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/submission.txt new file mode 100644 index 00000000..98dcbb84 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/340/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.getStringWidth "" \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/expected-value.txt new file mode 100644 index 00000000..bf0d87ab --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/expected-value.txt @@ -0,0 +1 @@ +4 \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/submission.txt new file mode 100644 index 00000000..d6b551c9 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/344/submission.txt @@ -0,0 +1 @@ +Bytes.Encode.getStringWidth "๐ŸŒฒ" \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/411/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/411/submission.txt new file mode 100644 index 00000000..8ac8e9d6 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/411/submission.txt @@ -0,0 +1 @@ +encodedBytes = Bytes.Encode.encode (Bytes.Encode.string "test") \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/expected-value.txt new file mode 100644 index 00000000..667cddf1 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/expected-value.txt @@ -0,0 +1 @@ +Just [116,101,115,116] \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/submission.txt new file mode 100644 index 00000000..d8e9b3fb --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/412/submission.txt @@ -0,0 +1 @@ +Bytes.Decode.decode (DecodeExtra.list 4 Bytes.Decode.unsignedInt8) encodedBytes \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/415/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/415/submission.txt new file mode 100644 index 00000000..9349c604 --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/415/submission.txt @@ -0,0 +1 @@ +encodedBytes = Bytes.Encode.encode (Bytes.Encode.string "๐ŸŒฒ") \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/expected-value.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/expected-value.txt new file mode 100644 index 00000000..97dc219c --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/expected-value.txt @@ -0,0 +1 @@ +Just [240,159,140,178] \ No newline at end of file diff --git a/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/submission.txt b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/submission.txt new file mode 100644 index 00000000..d8e9b3fb --- /dev/null +++ b/implement/test-and-train/elm-interactive-scenarios-kernel/elm-bytes/steps/416/submission.txt @@ -0,0 +1 @@ +Bytes.Decode.decode (DecodeExtra.list 4 Bytes.Decode.unsignedInt8) encodedBytes \ No newline at end of file diff --git a/implement/test-elm-time/ElmValueTests.cs b/implement/test-elm-time/ElmValueTests.cs index 022c1263..b69ff146 100644 --- a/implement/test-elm-time/ElmValueTests.cs +++ b/implement/test-elm-time/ElmValueTests.cs @@ -40,6 +40,11 @@ public void Elm_value_encoding_roundtrips() ElmValue.Integer(47)]), ]), + new ElmValue.ElmBytes(System.ReadOnlyMemory.Empty), + new ElmValue.ElmBytes((byte[])[0]), + new ElmValue.ElmBytes((byte[])[11, 13, 17]), + new ElmValue.ElmBytes((byte[])[0, 13, 17]), + ElmValue.ElmFloat.Convert(0), ElmValue.ElmFloat.Convert(0.3), ElmValue.ElmFloat.Convert(1.7), @@ -94,6 +99,18 @@ public void Elm_value_display_as_expression() (ElmValue.TagInstance("Just", [ElmValue.TagInstance("Just", [ElmValue.Integer(47)])]), "Just (Just 47)"), + (new ElmValue.ElmBytes(System.ReadOnlyMemory.Empty), + "<0 bytes>"), + + (new ElmValue.ElmBytes((byte[])[0]), + "<1 bytes>"), + + (new ElmValue.ElmBytes((byte[])[11, 13, 17]), + "<3 bytes>"), + + (new ElmValue.ElmBytes((byte[])[0, 13, 17]), + "<3 bytes>"), + (ElmValue.ElmFloat.Convert(0), "0"),