packages feed

proto-lens 0.7.0.0 → 0.7.1.0

raw patch · 8 files changed

+182/−130 lines, 8 filesdep ~basedep ~ghc-primdep ~lens-familyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: base, ghc-prim, lens-family, profunctors

API changes (from Hackage documentation)

- Data.ProtoLens.Labels: instance (Data.ProtoLens.Field.HasField s x a, p Data.Type.Equality.~ (a -> f a), q Data.Type.Equality.~ (s -> f s), GHC.Base.Functor f, a Data.Type.Equality.~ b) => GHC.OverloadedLabels.IsLabel x (p -> q)
+ Data.ProtoLens.Labels: instance (Data.ProtoLens.Field.HasField s x a, p GHC.Types.~ (a -> f a), q GHC.Types.~ (s -> f s), GHC.Base.Functor f, a GHC.Types.~ b) => GHC.OverloadedLabels.IsLabel x (p -> q)
+ Data.ProtoLens.Service.Types: packedServiceDescriptor :: Service s => Proxy s -> ByteString
- Data.ProtoLens.Encoding.Growing: data RealWorld :: Type
+ Data.ProtoLens.Encoding.Growing: data RealWorld

Files

Changelog.md view
@@ -1,5 +1,11 @@ # Changelog for `proto-lens` +## v0.7.1.0+- Support GHC 9.0.+- Fixed parsing of UTF8 chars in text format proto string literals.+- Support all valid text format boolean field values+- Remove redundant (.&. 127) from putVarInt (#396)+ ## v0.7.0.0 - Support GHC 8.10. - Add a method to `Data.ProtoLens.Message` for getting the `DescriptorProto`
proto-lens-imports/google/protobuf/compiler/plugin.proto view
@@ -45,11 +45,12 @@ // flag "--${NAME}_out" is passed to protoc.  syntax = "proto2";+ package google.protobuf.compiler; option java_package = "com.google.protobuf.compiler"; option java_outer_classname = "PluginProtos"; -option go_package = "github.com/golang/protobuf/protoc-gen-go/plugin;plugin_go";+option go_package = "google.golang.org/protobuf/types/pluginpb";  import "google/protobuf/descriptor.proto"; @@ -106,6 +107,16 @@   // exiting with a non-zero status code.   optional string error = 1; +  // A bitmask of supported features that the code generator supports.+  // This is a bitwise "or" of values from the Feature enum.+  optional uint64 supported_features = 2;++  // Sync with code_generator.h.+  enum Feature {+    FEATURE_NONE = 0;+    FEATURE_PROTO3_OPTIONAL = 1;+  }+   // Represents a single generated file.   message File {     // The file name, relative to the output directory.  The name must not@@ -162,6 +173,11 @@      // The file contents.     optional string content = 15;++    // Information describing the file content being inserted. If an insertion+    // point is used, this information will be appropriately offset and inserted+    // into the code generation metadata for the generated files.+    optional GeneratedCodeInfo generated_code_info = 16;   }   repeated File file = 15; }
proto-lens-imports/google/protobuf/descriptor.proto view
@@ -40,7 +40,8 @@ syntax = "proto2";  package google.protobuf;-option go_package = "github.com/golang/protobuf/protoc-gen-go/descriptor;descriptor";++option go_package = "google.golang.org/protobuf/types/descriptorpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "DescriptorProtos"; option csharp_namespace = "Google.Protobuf.Reflection";@@ -59,8 +60,8 @@  // Describes a complete .proto file. message FileDescriptorProto {-  optional string name = 1;       // file name, relative to root of source tree-  optional string package = 2;    // e.g. "foo", "foo.bar", etc.+  optional string name = 1;     // file name, relative to root of source tree+  optional string package = 2;  // e.g. "foo", "foo.bar", etc.    // Names of files imported by this file.   repeated string dependency = 3;@@ -100,8 +101,8 @@   repeated EnumDescriptorProto enum_type = 4;    message ExtensionRange {-    optional int32 start = 1;-    optional int32 end = 2;+    optional int32 start = 1;  // Inclusive.+    optional int32 end = 2;    // Exclusive.      optional ExtensionRangeOptions options = 3;   }@@ -115,8 +116,8 @@   // fields or extension ranges in the same message. Reserved ranges may   // not overlap.   message ReservedRange {-    optional int32 start = 1; // Inclusive.-    optional int32 end = 2;   // Exclusive.+    optional int32 start = 1;  // Inclusive.+    optional int32 end = 2;    // Exclusive.   }   repeated ReservedRange reserved_range = 9;   // Reserved field names, which may not be used by fields in the same message.@@ -128,6 +129,7 @@   // The parser stores options it doesn't recognize here. See above.   repeated UninterpretedOption uninterpreted_option = 999; +   // Clients can define custom options in extensions of this message. See above.   extensions 1000 to max; }@@ -137,42 +139,42 @@   enum Type {     // 0 is reserved for errors.     // Order is weird for historical reasons.-    TYPE_DOUBLE         = 1;-    TYPE_FLOAT          = 2;+    TYPE_DOUBLE = 1;+    TYPE_FLOAT = 2;     // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT64 if     // negative values are likely.-    TYPE_INT64          = 3;-    TYPE_UINT64         = 4;+    TYPE_INT64 = 3;+    TYPE_UINT64 = 4;     // Not ZigZag encoded.  Negative numbers take 10 bytes.  Use TYPE_SINT32 if     // negative values are likely.-    TYPE_INT32          = 5;-    TYPE_FIXED64        = 6;-    TYPE_FIXED32        = 7;-    TYPE_BOOL           = 8;-    TYPE_STRING         = 9;+    TYPE_INT32 = 5;+    TYPE_FIXED64 = 6;+    TYPE_FIXED32 = 7;+    TYPE_BOOL = 8;+    TYPE_STRING = 9;     // Tag-delimited aggregate.     // Group type is deprecated and not supported in proto3. However, Proto3     // implementations should still be able to parse the group wire format and     // treat group fields as unknown fields.-    TYPE_GROUP          = 10;-    TYPE_MESSAGE        = 11;  // Length-delimited aggregate.+    TYPE_GROUP = 10;+    TYPE_MESSAGE = 11;  // Length-delimited aggregate.      // New in version 2.-    TYPE_BYTES          = 12;-    TYPE_UINT32         = 13;-    TYPE_ENUM           = 14;-    TYPE_SFIXED32       = 15;-    TYPE_SFIXED64       = 16;-    TYPE_SINT32         = 17;  // Uses ZigZag encoding.-    TYPE_SINT64         = 18;  // Uses ZigZag encoding.-  };+    TYPE_BYTES = 12;+    TYPE_UINT32 = 13;+    TYPE_ENUM = 14;+    TYPE_SFIXED32 = 15;+    TYPE_SFIXED64 = 16;+    TYPE_SINT32 = 17;  // Uses ZigZag encoding.+    TYPE_SINT64 = 18;  // Uses ZigZag encoding.+  }    enum Label {     // 0 is reserved for errors-    LABEL_OPTIONAL      = 1;-    LABEL_REQUIRED      = 2;-    LABEL_REPEATED      = 3;-  };+    LABEL_OPTIONAL = 1;+    LABEL_REQUIRED = 2;+    LABEL_REPEATED = 3;+  }    optional string name = 1;   optional int32 number = 3;@@ -211,6 +213,29 @@   optional string json_name = 10;    optional FieldOptions options = 8;++  // If true, this is a proto3 "optional". When a proto3 field is optional, it+  // tracks presence regardless of field type.+  //+  // When proto3_optional is true, this field must be belong to a oneof to+  // signal to old proto3 clients that presence is tracked for this field. This+  // oneof is known as a "synthetic" oneof, and this field must be its sole+  // member (each proto3 optional field gets its own synthetic oneof). Synthetic+  // oneofs exist in the descriptor only, and do not generate any API. Synthetic+  // oneofs must be ordered after all "real" oneofs.+  //+  // For message fields, proto3_optional doesn't create any semantic change,+  // since non-repeated message fields always track presence. However it still+  // indicates the semantic detail of whether the user wrote "optional" or not.+  // This can be useful for round-tripping the .proto file. For consistency we+  // give message fields a synthetic oneof also, even though it is not required+  // to track presence. This is especially important because the parser can't+  // tell if a field is a message or an enum, so it must always create a+  // synthetic oneof.+  //+  // Proto2 optional fields do not set this flag, because they already indicate+  // optional with `LABEL_OPTIONAL`.+  optional bool proto3_optional = 17; }  // Describes a oneof.@@ -234,8 +259,8 @@   // is inclusive such that it can appropriately represent the entire int32   // domain.   message EnumReservedRange {-    optional int32 start = 1; // Inclusive.-    optional int32 end = 2;   // Inclusive.+    optional int32 start = 1;  // Inclusive.+    optional int32 end = 2;    // Inclusive.   }    // Range of reserved numeric values. Reserved numeric values may not be used@@ -276,9 +301,9 @@   optional MethodOptions options = 4;    // Identifies if client streams multiple client messages-  optional bool client_streaming = 5 [default=false];+  optional bool client_streaming = 5 [default = false];   // Identifies if server streams multiple server messages-  optional bool server_streaming = 6 [default=false];+  optional bool server_streaming = 6 [default = false]; }  @@ -314,7 +339,6 @@ //   If this turns out to be popular, a web service will be set up //   to automatically assign option numbers. - message FileOptions {    // Sets the Java package where classes generated from this .proto will be@@ -337,7 +361,7 @@   // named by java_outer_classname.  However, the outer class will still be   // generated to contain the file's getDescriptor() method as well as any   // top-level extensions defined in the file.-  optional bool java_multiple_files = 10 [default=false];+  optional bool java_multiple_files = 10 [default = false];    // This option does nothing.   optional bool java_generate_equals_and_hash = 20 [deprecated=true];@@ -348,17 +372,17 @@   // Message reflection will do the same.   // However, an extension field still accepts non-UTF-8 byte sequences.   // This option has no effect on when used with the lite runtime.-  optional bool java_string_check_utf8 = 27 [default=false];+  optional bool java_string_check_utf8 = 27 [default = false];     // Generated classes can be optimized for speed or code size.   enum OptimizeMode {-    SPEED = 1;        // Generate complete code for parsing, serialization,-                      // etc.-    CODE_SIZE = 2;    // Use ReflectionOps to implement these methods.-    LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.+    SPEED = 1;         // Generate complete code for parsing, serialization,+                       // etc.+    CODE_SIZE = 2;     // Use ReflectionOps to implement these methods.+    LITE_RUNTIME = 3;  // Generate code using MessageLite and the lite runtime.   }-  optional OptimizeMode optimize_for = 9 [default=SPEED];+  optional OptimizeMode optimize_for = 9 [default = SPEED];    // Sets the Go package where structs generated from this .proto will be   // placed. If omitted, the Go package will be derived from the following:@@ -369,6 +393,7 @@   +   // Should generic services be generated in each language?  "Generic" services   // are not specific to any particular RPC system.  They are generated by the   // main code generators in each language (without additional plugins).@@ -379,20 +404,20 @@   // that generate code specific to your particular RPC system.  Therefore,   // these default to false.  Old code which depends on generic services should   // explicitly set them to true.-  optional bool cc_generic_services = 16 [default=false];-  optional bool java_generic_services = 17 [default=false];-  optional bool py_generic_services = 18 [default=false];-  optional bool php_generic_services = 42 [default=false];+  optional bool cc_generic_services = 16 [default = false];+  optional bool java_generic_services = 17 [default = false];+  optional bool py_generic_services = 18 [default = false];+  optional bool php_generic_services = 42 [default = false];    // Is this file deprecated?   // Depending on the target platform, this can emit Deprecated annotations   // for everything in the file, or it will be completely ignored; in the very   // least, this is a formalization for deprecating files.-  optional bool deprecated = 23 [default=false];+  optional bool deprecated = 23 [default = false];    // Enables the use of arenas for the proto messages in this file. This applies   // only to generated classes for C++.-  optional bool cc_enable_arenas = 31 [default=false];+  optional bool cc_enable_arenas = 31 [default = true];     // Sets the objective c class prefix which is prepended to all objective c@@ -417,10 +442,9 @@   // determining the namespace.   optional string php_namespace = 41; -   // Use this option to change the namespace of php generated metadata classes.-  // Default is empty. When this option is empty, the proto file name will be used-  // for determining the namespace.+  // Default is empty. When this option is empty, the proto file name will be+  // used for determining the namespace.   optional string php_metadata_namespace = 44;    // Use this option to change the package of ruby generated classes. Default@@ -428,6 +452,7 @@   // determining the ruby package.   optional string ruby_package = 45; +   // The parser stores options it doesn't recognize here.   // See the documentation for the "Options" section above.   repeated UninterpretedOption uninterpreted_option = 999;@@ -458,18 +483,18 @@   //   // Because this is an option, the above two restrictions are not enforced by   // the protocol compiler.-  optional bool message_set_wire_format = 1 [default=false];+  optional bool message_set_wire_format = 1 [default = false];    // Disables the generation of the standard "descriptor()" accessor, which can   // conflict with a field of the same name.  This is meant to make migration   // from proto1 easier; new code should avoid fields named "descriptor".-  optional bool no_standard_descriptor_accessor = 2 [default=false];+  optional bool no_standard_descriptor_accessor = 2 [default = false];    // Is this message deprecated?   // Depending on the target platform, this can emit Deprecated annotations   // for the message, or it will be completely ignored; in the very least,   // this is a formalization for deprecating messages.-  optional bool deprecated = 3 [default=false];+  optional bool deprecated = 3 [default = false];    // Whether the message is an automatically generated map entry type for the   // maps field.@@ -486,7 +511,7 @@   //   // Implementations may choose not to generate the map_entry=true message, but   // use a native map in the target language to hold the keys and values.-  // The reflection APIs in such implementions still need to work as+  // The reflection APIs in such implementations still need to work as   // if the field is a repeated message field.   //   // NOTE: Do not set the option in .proto files. Always use the maps syntax@@ -497,6 +522,7 @@   reserved 8;  // javalite_serializable   reserved 9;  // javanano_as_lite +   // The parser stores options it doesn't recognize here. See above.   repeated UninterpretedOption uninterpreted_option = 999; @@ -576,16 +602,16 @@   // implementation must either *always* check its required fields, or *never*   // check its required fields, regardless of whether or not the message has   // been parsed.-  optional bool lazy = 5 [default=false];+  optional bool lazy = 5 [default = false];    // Is this field deprecated?   // Depending on the target platform, this can emit Deprecated annotations   // for accessors, or it will be completely ignored; in the very least, this   // is a formalization for deprecating fields.-  optional bool deprecated = 3 [default=false];+  optional bool deprecated = 3 [default = false];    // For Google-internal migration only. Do not use.-  optional bool weak = 10 [default=false];+  optional bool weak = 10 [default = false];     // The parser stores options it doesn't recognize here. See above.@@ -615,7 +641,7 @@   // Depending on the target platform, this can emit Deprecated annotations   // for the enum, or it will be completely ignored; in the very least, this   // is a formalization for deprecating enums.-  optional bool deprecated = 3 [default=false];+  optional bool deprecated = 3 [default = false];    reserved 5;  // javanano_as_lite @@ -631,7 +657,7 @@   // Depending on the target platform, this can emit Deprecated annotations   // for the enum value, or it will be completely ignored; in the very least,   // this is a formalization for deprecating enum values.-  optional bool deprecated = 1 [default=false];+  optional bool deprecated = 1 [default = false];    // The parser stores options it doesn't recognize here. See above.   repeated UninterpretedOption uninterpreted_option = 999;@@ -651,7 +677,7 @@   // Depending on the target platform, this can emit Deprecated annotations   // for the service, or it will be completely ignored; in the very least,   // this is a formalization for deprecating services.-  optional bool deprecated = 33 [default=false];+  optional bool deprecated = 33 [default = false];    // The parser stores options it doesn't recognize here. See above.   repeated UninterpretedOption uninterpreted_option = 999;@@ -671,18 +697,18 @@   // Depending on the target platform, this can emit Deprecated annotations   // for the method, or it will be completely ignored; in the very least,   // this is a formalization for deprecating methods.-  optional bool deprecated = 33 [default=false];+  optional bool deprecated = 33 [default = false];    // Is this method side-effect-free (or safe in HTTP parlance), or idempotent,   // or neither? HTTP based RPC implementation may choose GET verb for safe   // methods, and PUT verb for idempotent methods instead of the default POST.   enum IdempotencyLevel {     IDEMPOTENCY_UNKNOWN = 0;-    NO_SIDE_EFFECTS     = 1; // implies idempotent-    IDEMPOTENT          = 2; // idempotent, but may have side effects+    NO_SIDE_EFFECTS = 1;  // implies idempotent+    IDEMPOTENT = 2;       // idempotent, but may have side effects   }-  optional IdempotencyLevel idempotency_level =-      34 [default=IDEMPOTENCY_UNKNOWN];+  optional IdempotencyLevel idempotency_level = 34+      [default = IDEMPOTENCY_UNKNOWN];    // The parser stores options it doesn't recognize here. See above.   repeated UninterpretedOption uninterpreted_option = 999;@@ -763,7 +789,7 @@   //   beginning of the "extend" block and is shared by all extensions within   //   the block.   // - Just because a location's span is a subset of some other location's span-  //   does not mean that it is a descendent.  For example, a "group" defines+  //   does not mean that it is a descendant.  For example, a "group" defines   //   both a type and a field in a single declaration.  Thus, the locations   //   corresponding to the type and field and their components will overlap.   // - Code which tries to interpret locations should probably be designed to@@ -794,14 +820,14 @@     //   [ 4, 3, 2, 7 ]     // this path refers to the whole field declaration (from the beginning     // of the label to the terminating semicolon).-    repeated int32 path = 1 [packed=true];+    repeated int32 path = 1 [packed = true];      // Always has exactly three or four elements: start line, start column,     // end line (optional, otherwise assumed same as start line), end column.     // These are packed into a single field for efficiency.  Note that line     // and column numbers are zero-based -- typically you will want to add     // 1 to each before displaying to a user.-    repeated int32 span = 2 [packed=true];+    repeated int32 span = 2 [packed = true];      // If this SourceCodeInfo represents a complete declaration, these are any     // comments appearing before and after the declaration which appear to be@@ -866,7 +892,7 @@   message Annotation {     // Identifies the element in the original source .proto file. This field     // is formatted the same as SourceCodeInfo.Location.path.-    repeated int32 path = 1 [packed=true];+    repeated int32 path = 1 [packed = true];      // Identifies the filesystem path to the original source .proto.     optional string source_file = 2;
proto-lens.cabal view
@@ -1,13 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.33.0.+-- This file has been generated from package.yaml by hpack version 0.34.4. -- -- see: https://github.com/sol/hpack------ hash: d71629464ee51493ce31ad480ec5872af89ba3c917588b69a61484409a22896c  name:           proto-lens-version:        0.7.0.0+version:        0.7.1.0 synopsis:       A lens-based implementation of protocol buffers in Haskell. description:    The proto-lens library provides an API for protocol buffers using modern Haskell language and library patterns.  Specifically, it provides:                 .@@ -60,16 +58,16 @@   hs-source-dirs:       src   build-depends:-      base >=4.10 && <4.15+      base >=4.10 && <4.16     , bytestring ==0.10.*     , containers >=0.5 && <0.7     , deepseq ==1.4.*-    , ghc-prim >=0.4 && <0.7-    , lens-family >=1.2 && <2.1+    , ghc-prim >=0.4 && <0.8+    , lens-family >=1.2 && <2.2     , parsec ==3.1.*     , pretty ==1.1.*     , primitive >=0.6 && <0.8-    , profunctors >=5.2 && <5.6+    , profunctors >=5.2 && <6.0     , tagged ==0.8.*     , text ==1.2.*     , transformers >=0.4 && <0.6
src/Data/ProtoLens/Encoding/Bytes.hs view
@@ -51,7 +51,7 @@ import Control.Monad.Trans.Except (throwE, ExceptT) import Data.Bits import Data.ByteString (ByteString)-import Data.ByteString.Lazy.Builder as Builder+import Data.ByteString.Builder as Builder import qualified Data.ByteString.Builder.Internal as Internal import qualified Data.ByteString.Lazy as L import Data.Int (Int32, Int64)@@ -126,7 +126,7 @@ putVarInt :: Word64 -> Builder putVarInt n     | n < 128 = Builder.word8 (fromIntegral n)-    | otherwise = Builder.word8 (fromIntegral $ n .&. 127 .|. 128)+    | otherwise = Builder.word8 (fromIntegral $ n .|. 128)                       <> putVarInt (n `shiftR` 7)  getFixed32 :: Parser Word32
src/Data/ProtoLens/Service/Types.hs view
@@ -23,8 +23,10 @@   , StreamingType (..)   ) where -import Data.Kind (Constraint)+import qualified Data.ByteString as B+import Data.Kind (Constraint, Type) import Data.ProtoLens.Message (Message)+import Data.Proxy (Proxy(..)) import GHC.TypeLits  @@ -53,6 +55,7 @@   type ServicePackage s :: Symbol   type ServiceMethods s :: [Symbol] +  packedServiceDescriptor :: Proxy s -> B.ByteString  ------------------------------------------------------------------------------ -- | Data type to be used as a promoted type for 'MethodStreamingType'.@@ -82,8 +85,8 @@       , Message (MethodOutput s m)       ) => HasMethodImpl s (m :: Symbol) where   type MethodName          s m :: Symbol-  type MethodInput         s m :: *-  type MethodOutput        s m :: *+  type MethodInput         s m :: Type+  type MethodOutput        s m :: Type   type MethodStreamingType s m :: StreamingType  
src/Data/ProtoLens/TextFormat.hs view
@@ -317,8 +317,8 @@ makeScalarValue DoubleField (Parser.DoubleValue x) = Right x makeScalarValue FloatField (Parser.DoubleValue x) = Right (realToFrac x) makeScalarValue BoolField (Parser.EnumValue x)-    | x == "true" = Right True-    | x == "false" = Right False+    | x `elem` ["true", "True", "t"] = Right True+    | x `elem` ["false", "False", "f"] = Right False     | otherwise = Left $ "Unrecognized bool value " ++ show x makeScalarValue StringField (Parser.ByteStringValue x) = Right (Text.decodeUtf8 x) makeScalarValue BytesField (Parser.ByteStringValue x) = Right x
src/Data/ProtoLens/TextFormat/Parser.hs view
@@ -16,23 +16,23 @@     , parser     ) where -import Data.ByteString (ByteString, pack)-import Data.Char (ord, isSpace)+import Control.Applicative ((<|>), many)+import Control.Monad (liftM, liftM2, mzero, unless)+import Data.ByteString (ByteString)+import Data.ByteString.Builder (Builder, char8, charUtf8, toLazyByteString, word8)+import Data.ByteString.Lazy (toStrict)+import Data.Char (digitToInt, isSpace)+import Data.Functor (($>)) import Data.Functor.Identity (Identity) import Data.List (intercalate)-import Data.Maybe (catMaybes)-import Data.Text.Lazy (Text) import qualified Data.Text as StrictText-import Data.Word (Word8)-import Numeric (readOct, readHex)+import Data.Text.Lazy (Text) import Text.Parsec ((<?>)) import Text.Parsec.Char   (alphaNum, char, hexDigit, letter, octDigit, oneOf, satisfy) import Text.Parsec.Text.Lazy (Parser)-import Text.Parsec.Combinator (choice, eof, many1, optionMaybe, sepBy1)+import Text.Parsec.Combinator (choice, eof, many1, sepBy1) import Text.Parsec.Token hiding (octal)-import Control.Applicative ((<|>), many)-import Control.Monad (liftM, liftM2, mzero)  -- | A 'TokenParser' for the protobuf text format. ptp :: GenTokenParser Text () Identity@@ -55,7 +55,6 @@   , caseSensitive = True   } - type Message = [Field]  data Field = Field Key Value@@ -131,39 +130,43 @@ protoStringLiteral :: Parser ByteString protoStringLiteral = do     initialQuoteChar <- char '\'' <|> char '\"'-    word8s <- many $ stringChar initialQuoteChar+    let quoted = do+          _ <- char '\\'+          choice+            [ char 'a'   $> char8 '\a'+            , char 'b'   $> char8 '\b'+            , char 'f'   $> char8 '\f'+            , char 'n'   $> char8 '\n'+            , char 'r'   $> char8 '\r'+            , char 't'   $> char8 '\t'+            , char 'v'   $> char8 '\v'+            , char '\\'  $> char8 '\\'+            , char '\''  $> char8 '\''+            , char '\"'  $> char8 '\"'+            , oneOf "xX" *> parse8BitToBuilder hexDigit 16 (1, 2)+            , oneOf "uU" *> fail "Unicode in string literals not yet supported"+            ,               parse8BitToBuilder octDigit 8 (1, 3)+            ]+        unquoted = charUtf8 <$> satisfy (/= initialQuoteChar)+    builders <- many $ quoted <|> unquoted     _ <- char initialQuoteChar-    return $ pack word8s+    return $ toStrict $ toLazyByteString $ mconcat builders   where-    stringChar :: Char -> Parser Word8-    stringChar quote = (nonEscape quote) <|> stringEscape-    nonEscape quote = fmap (fromIntegral . ord)-        $ satisfy (\c -> c `notElem` "\\" ++ [quote] && ord c < 256)-    stringEscape = char '\\' >> (octal <|> hex <|> unicode <|> simple)-    octal = do d0 <- octDigit-               d1 <- optionMaybe octDigit-               d2 <- optionMaybe octDigit-               readMaybeDigits readOct [Just d0, d1, d2]-    readMaybeDigits :: ReadS Word8 -> [Maybe Char] -> Parser Word8-    readMaybeDigits reader-        = return . (\str -> let [(v, "")] = reader str in v) . catMaybes-    hex = do _ <- oneOf "xX"-             d0 <- hexDigit-             d1 <- optionMaybe hexDigit-             readMaybeDigits readHex [Just d0, d1]-    unicode = oneOf "uU" >> fail "Unicode in string literals not yet supported"-    simple = choice $ map charRet [ ('a', '\a')-                                  , ('b', '\b')-                                  , ('f', '\f')-                                  , ('n', '\n')-                                  , ('r', '\r')-                                  , ('t', '\t')-                                  , ('v', '\v')-                                  , ('\\', '\\')-                                  , ('\'', '\'')-                                  , ('\"', '\"')-                                  ]-      where-        charRet :: (Char, Char) -> Parser Word8-        charRet (escapeCh, ch) = do _ <- char escapeCh-                                    return $ fromIntegral $ ord ch+    -- | Apply a parser between 'min' and 'max' times, failing otherwise.+    manyN :: Parser a -> (Int, Int) -> Parser [a]+    manyN _ (_, 0) = return []+    manyN p (0, maX) = ((:) <$> p <*> manyN p (0, maX - 1)) <|> pure []+    manyN p (miN, maX) = (:) <$> p <*> manyN p (miN - 1, maX - 1)++    -- | Parse a number in 'base' with between 'min' and 'max' digits.+    parseNum :: Parser Char -> Int -> (Int, Int) -> Parser Int+    parseNum p base range = do+      digits <- map digitToInt <$> manyN p range+      return $ foldl (\a d -> a * base + d) 0 digits++    -- | Parse a number and return a builder for the 8-bit char it represents.+    parse8BitToBuilder :: Parser Char -> Int -> (Int, Int) -> Parser Builder+    parse8BitToBuilder p base range = do+      value <- parseNum p base range+      unless (value < 256) $ fail "Escaped number is not 8-bit"+      return $ word8 $ fromIntegral value