git.iko.soy/rowtype-yoga/purescript-protobuf
on master help sign in
Plugin is running
commitd8aff82fb2dc582a9c509277c238a0ce847ca41e authorJames Brock <jamesbrock@gmail.com> dateTue 8 Sep 2020, 14:13 (6 years ago) parentffacadb
8 files changed+120−42
README.md+11−5 bin/protoc-gen-purescript+1−1 package-lock.json+13 package.json+10 shell.nix+2−1 src/Protobuf/Common.purs+5 src/ProtocPlugin/Main.purs+73−35 test/test.proto+5
README.md+11−5
@@ -9,8 +9,8 @@ supported.
99## Runtime library
1010
1111This library operates on
12−[`ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer), so works in both
13−[Node](https://pursuit.purescript.org/packages/purescript-node-buffer/docs/Node.Buffer.Class)
12+[`ArrayBuffer`](https://pursuit.purescript.org/packages/purescript-arraybuffer-types/docs/Data.ArrayBuffer.Types#t:ArrayBuffer), so
13+[works in both Node](https://pursuit.purescript.org/packages/purescript-node-buffer/docs/Node.Buffer.Class)
1414and browser runtime environments.
1515
1616## Compile-time Code Generation
@@ -19,14 +19,20 @@ The `shell.nix` environment provides
1919
2020* The Purescript toolchain
2121* The `protoc` compiler
22−* The `bin/protoc-gen-purescript` executable on the `PATH`
22+* The `protoc` compiler plugin for Purescript. The `bin/protoc-gen-purescript`
23+ executable is on the `PATH`
2324 [so that `protoc` can find it](https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.compiler.plugin).
2425
25−Enter the Nix shell and run `protoc` with the directory `OUT_DIR` name
26+Enter the Nix shell.
27+
28+```
29+nix-shell
30+```
31+
32+Run `protoc` with the directory `OUT_DIR` name
2633for the generated `.purs` files, and the `$PROTO_FILES` list of input
2734`.proto` files.
2835
2936```
30−nix-shell
3137protoc --purescript_out=$OUT_DIR $PROTO_FILES
3238```
bin/protoc-gen-purescript+1−1
@@ -1 +1 @@
1−cd ..; spago run --quiet --main ProtocPlugin.Main --node-args "$@"
1+spago run --main ProtocPlugin.Main
package-lock.jsonnew file+13
@@ -0,0 +1,13 @@
1+{
2+ "name": "purescript-protobuf",
3+ "version": "0.1.0",
4+ "lockfileVersion": 1,
5+ "requires": true,
6+ "dependencies": {
7+ "long": {
8+ "version": "4.0.0",
9+ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
10+ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
11+ }
12+ }
13+}
package.jsonnew file+10
@@ -0,0 +1,10 @@
1+{
2+ "name": "purescript-protobuf",
3+ "version": "0.1.0",
4+ "description": "Google Protocol Buffers",
5+ "author": "Cross Compass, LLC.",
6+ "license": "BSD-3-Clause",
7+ "dependencies": {
8+ "long": "^4.0.0"
9+ }
10+}
shell.nix+2−1
@@ -23,6 +23,7 @@ pkgs.mkShell {
2323 echo "Purescript Protobuf development environment."
2424 echo "To build purescript-protobuf, run this command:"
2525 echo ""
26+ echo " npm install"
2627 echo " spago build"
2728 echo ""
2829 echo "To test purescript-protobuf, run this command:"
@@ -31,7 +32,7 @@ pkgs.mkShell {
3132 echo ""
3233 echo "To generate Purescript files from .proto files, run this command:"
3334 echo ""
34− echo " protoc --purescript_out=\$OUT_DIR \$PROTO_FILES"
35+ echo " protoc --purescript_out=./test test/test.proto"
3536 echo ""
3637 '';
3738 LC_ALL = "C.UTF-8"; # https://github.com/purescript/spago/issues/507
src/Protobuf/Common.purs+5
@@ -8,6 +8,8 @@ import Prelude
88import Data.UInt (UInt)
99import Data.Enum (class Enum, fromEnum, class BoundedEnum, Cardinality(..))
1010import Data.Maybe (Maybe(..))
11+import Data.Generic.Rep(class Generic)
12+import Data.Generic.Rep.Show (genericShow)
1113
1214type FieldNumber = UInt
1315
@@ -19,6 +21,7 @@ data WireType
1921 | Bits32
2022
2123derive instance eqWireType :: Eq WireType
24+derive instance genericWireType :: Generic WireType _
2225
2326instance ordWireType :: Ord WireType
2427 where
@@ -53,3 +56,5 @@ instance boundedEnumWireType :: BoundedEnum WireType
5356 fromEnum LenDel = 2
5457 fromEnum Bits32 = 5
5558
59+instance showWireType :: Show WireType where show = genericShow
60+
src/ProtocPlugin/Main.purs+73−35
@@ -9,11 +9,13 @@ import Data.Array (snoc)
99import Data.Foldable (foldl)
1010import Data.Symbol (SProxy(..))
1111import Data.Tuple (Tuple(..))
12+import Data.Generic.Rep(class Generic)
13+import Data.Generic.Rep.Show (genericShow)
1214import Data.Long.Unsigned (toInt)
1315import Data.UInt (UInt)
1416import Data.UInt as UInt
1517
16−import Text.Parsing.Parser (ParserT, fail)
18+import Text.Parsing.Parser (ParserT, fail, runParserT)
1719import Text.Parsing.Parser.Combinators (manyTill)
1820import Text.Parsing.Parser.DataView (eof, takeN)
1921
@@ -24,11 +26,12 @@ import Protobuf.Decode as Decode
2426-- import Protobuf.Encode as Encode
2527import Protobuf.Common (WireType(..))
2628
27−import Node.Process (stdin, stdout)
29+import Node.Process (stdin, stdout, stderr)
2830import Node.Stream (read, writeString, onReadable)
2931import Node.Buffer (toArrayBuffer)
3032import Node.Encoding (Encoding(..))
31−import Data.ArrayBuffer.ArrayBuffer as AB
33+-- import Data.ArrayBuffer.ArrayBuffer as AB
34+import Data.ArrayBuffer.DataView as DV
3235import Data.ArrayBuffer.Types (DataView)
3336
3437main :: Effect Unit
@@ -39,31 +42,34 @@ main = do
3942 Nothing -> pure unit
4043 Just stdinbuf -> do
4144 stdinab <- toArrayBuffer stdinbuf
42− void $ writeString stdout UTF8 (show $ AB.byteLength stdinab) (pure unit)
45+ -- void $ writeString stdout UTF8 (show $ AB.byteLength stdinab) (pure unit)
46+ let stdinview = DV.whole stdinab
47+ request <- runParserT stdinview parseCodeGeneratorRequest
48+ void $ writeString stderr UTF8 (show request) (pure unit)
4349
44−type CodeGeneratorRequestBuilder = RecordB.Builder CodeGeneratorRequestRow CodeGeneratorRequestRow
50+type CodeGeneratorRequestBuilder = RecordB.Builder CodeGeneratorRequestR CodeGeneratorRequestR
4551
46−parseCodeGeneratorRequest :: ParserT DataView Effect CodeGeneratorRequestRow
52+parseCodeGeneratorRequest :: ParserT DataView Effect CodeGeneratorRequest
4753parseCodeGeneratorRequest = do
4854 builders <- manyTill parseField eof
49− pure $ build (foldl (>>>) identity builders) defaultCodeGeneratorRequest
55+ pure $ CodeGeneratorRequest $ build (foldl (>>>) identity builders) defaultCodeGeneratorRequest
5056 where
5157 parseField :: ParserT DataView Effect CodeGeneratorRequestBuilder
5258 parseField = do
5359 Tuple fieldNumber wireType <- Decode.tag32
5460 case unit of
55− _ | fieldNumber == fn_CodeGeneratorRequestRow_file_to_generate -> do
61+ _ | fieldNumber == fn_CodeGeneratorRequest_file_to_generate -> do
5662 x <- Decode.string
57− pure $ modify fs_CodeGeneratorRequestRow_file_to_generate $ flip snoc x
58− | fieldNumber == fn_CodeGeneratorRequestRow_parameter -> do
63+ pure $ modify fs_CodeGeneratorRequest_file_to_generate $ flip snoc x
64+ | fieldNumber == fn_CodeGeneratorRequest_parameter -> do
5965 x <- Decode.string
60− pure $ modify fs_CodeGeneratorRequestRow_parameter $ const $ Just x
61− -- | fieldNumber == fn_CodeGeneratorRequestRow_proto_file -> do
66+ pure $ modify fs_CodeGeneratorRequest_parameter $ const $ Just x
67+ -- | fieldNumber == fn_CodeGeneratorRequest_proto_file -> do
6268 -- x <- parseFileDescriptorProto
63− -- pure $ modify fs_CodeGeneratorRequestRow_proto_file $ flip snoc x
64− -- | fieldNumber == fn_CodeGeneratorRequestRow_compiler_version -> do
69+ -- pure $ modify fs_CodeGeneratorRequest_proto_file $ flip snoc x
70+ -- | fieldNumber == fn_CodeGeneratorRequest_compiler_version -> do
6571 -- x <- parseVersion
66− -- pure $ modify fs_CodeGeneratorRequestRow_compiler_version $ const $ Just x
72+ -- pure $ modify fs_CodeGeneratorRequest_compiler_version $ const $ Just x
6773 _ -> parseUnknownField wireType *> pure identity
6874
6975 -- IMPORTANT For embedded message fields, the parser merges multiple instances of the same field,
@@ -86,44 +92,56 @@ parseUnknownField wireType = case wireType of
8692
8793-- https://pursuit.purescript.org/packages/purescript-record
8894
95+-- IMPORTANT We need to wrap our structural record types in a nominal
96+-- data type so that we can nest records.
97+-- https://github.com/purescript/documentation/blob/master/errors/CycleInTypeSynonym.md
98+-- And so that we can assign instances?
99+newtype CodeGeneratorRequest = CodeGeneratorRequest CodeGeneratorRequestR
100+derive instance genericCodeGeneratorRequest :: Generic CodeGeneratorRequest _
101+instance showCodeGeneratorRequest :: Show CodeGeneratorRequest where show = genericShow
89102-- | Data type for a CodeGenerationRequest message.
90103-- | https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.compiler.plugin.pb
91−-- data CodeGeneratorRequest = CodeGeneratorRequest CodeGeneratorRequestRow
92−-- derive instance showCodeGeneratorRequest :: Show CodeGeneratorRequest
93−type CodeGeneratorRequestRow =
104+type CodeGeneratorRequestR =
94105 { file_to_generate :: Array String -- 1
95106 , parameter :: Maybe String -- 2
96107 , proto_file :: Array FileDescriptorProto -- 15
97108 , compiler_version :: Maybe Version -- 3
98109 }
99−defaultCodeGeneratorRequest :: CodeGeneratorRequestRow
110+
111+defaultCodeGeneratorRequest :: CodeGeneratorRequestR
100112defaultCodeGeneratorRequest =
101113 { file_to_generate: []
102114 , parameter: Nothing
103115 , proto_file: []
104116 , compiler_version: Nothing
105117 }
106−fs_CodeGeneratorRequestRow_file_to_generate = SProxy :: SProxy "file_to_generate"
107−fs_CodeGeneratorRequestRow_parameter = SProxy :: SProxy "parameter"
108−fs_CodeGeneratorRequestRow_proto_file = SProxy :: SProxy "proto_file"
109−fs_CodeGeneratorRequestRow_compiler_version = SProxy :: SProxy "compiler_version"
110−fn_CodeGeneratorRequestRow_file_to_generate = UInt.fromInt 1 :: UInt
111−fn_CodeGeneratorRequestRow_parameter = UInt.fromInt 2 :: UInt
112−fn_CodeGeneratorRequestRow_proto_file = UInt.fromInt 15 :: UInt
113−fn_CodeGeneratorRequestRow_compiler_version = UInt.fromInt 3 :: UInt
118+fs_CodeGeneratorRequest_file_to_generate = SProxy :: SProxy "file_to_generate"
119+fs_CodeGeneratorRequest_parameter = SProxy :: SProxy "parameter"
120+fs_CodeGeneratorRequest_proto_file = SProxy :: SProxy "proto_file"
121+fs_CodeGeneratorRequest_compiler_version = SProxy :: SProxy "compiler_version"
122+fn_CodeGeneratorRequest_file_to_generate = UInt.fromInt 1 :: UInt
123+fn_CodeGeneratorRequest_parameter = UInt.fromInt 2 :: UInt
124+fn_CodeGeneratorRequest_proto_file = UInt.fromInt 15 :: UInt
125+fn_CodeGeneratorRequest_compiler_version = UInt.fromInt 3 :: UInt
114126
115127-- | The version number of protocol compiler.
116−data Version = Version
128+newtype Version = Version VersionR
129+derive instance genericVersion :: Generic Version _
130+instance showVersion :: Show Version where show = genericShow
131+type VersionR =
117132 { major :: Maybe Int --1
118133 , minor :: Maybe Int --2
119134 , patch :: Maybe Int --3
120135 , suffix :: Maybe String -- 4
121136 }
122137
138+newtype FileDescriptorProto = FileDescriptorProto FileDescriptorProtoR
139+derive instance genericFileDescriptorProto :: Generic FileDescriptorProto _
140+instance showFileDescriptorProto :: Show FileDescriptorProto where show = const "" -- TODO genericShow
123141-- | Describes a complete .proto file.
124142-- | https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.descriptor.pb
125143-- | The syntax for decoding this is "proto2"?
126−data FileDescriptorProto = FileDescriptorProto
144+type FileDescriptorProtoR =
127145 { name :: Maybe String -- 1
128146 , package :: Maybe String -- 2
129147 , dependency :: Array String -- 3
@@ -137,8 +155,11 @@ data FileDescriptorProto = FileDescriptorProto
137155 , syntax :: Maybe String -- 12
138156 }
139157
158+newtype DescriptorProto = DescriptorProto DescriptorProtoR
159+derive instance genericDescriptorProto :: Generic DescriptorProto _
160+instance showDescriptorProto :: Show DescriptorProto where show = const "" -- TODO genericShow
140161-- | Describes a message type.
141−data DescriptorProto = DescriptorProto
162+type DescriptorProtoR =
142163 { name :: Maybe String -- 1
143164 , field :: Array FieldDescriptorProto -- 2
144165 , extension :: Array FieldDescriptorProto -- 6
@@ -150,7 +171,10 @@ data DescriptorProto = DescriptorProto
150171 -- TODO eh who cares about reserved ranges
151172 }
152173
153−data DescriptorProto_ExtensionRange = DescriptorProto_ExtensionRange
174+newtype DescriptorProto_ExtensionRange = DescriptorProto_ExtensionRange DescriptorProto_ExtensionRangeR
175+derive instance genericDescriptorProto_ExtensionRange :: Generic DescriptorProto_ExtensionRange _
176+instance showDescriptorProto_ExtensionRange :: Show DescriptorProto_ExtensionRange where show = genericShow
177+type DescriptorProto_ExtensionRangeR =
154178 { start :: Maybe Int -- 1
155179 , end :: Maybe Int -- 2
156180 -- TODO , options :: Maybe ExtensionRangeOptions
@@ -163,9 +187,14 @@ data DescriptorProto_ExtensionRange = DescriptorProto_ExtensionRange
163187-- }
164188
165189data FieldDescriptorProto_Label = OPTIONAL | REQUIRED | REPEATED
190+derive instance genericFieldDescriptorProto_Label :: Generic FieldDescriptorProto_Label _
191+instance showFieldDescriptorProto_Label :: Show FieldDescriptorProto_Label where show = genericShow
166192
167193-- | Describes a field within a message.
168−data FieldDescriptorProto = FieldDescriptorProto
194+newtype FieldDescriptorProto = FieldDescriptorProto FieldDescriptorProtoR
195+derive instance genericFieldDescriptorProto :: Generic FieldDescriptorProto _
196+instance showFieldDescriptorProto :: Show FieldDescriptorProto where show = genericShow
197+type FieldDescriptorProtoR =
169198 { name :: Maybe String -- 1
170199 , number :: Maybe Int -- 3
171200 , label :: Maybe FieldDescriptorProto_Label -- 4
@@ -179,13 +208,19 @@ data FieldDescriptorProto = FieldDescriptorProto
179208 }
180209
181210-- | Describes a oneof.
182−data OneofDescriptorProto = OneofDescriptorProto
211+newtype OneofDescriptorProto = OneofDescriptorProto OneofDescriptorProtoR
212+derive instance genericOneofDescriptorProto :: Generic OneofDescriptorProto _
213+instance showOneofDescriptorProto :: Show OneofDescriptorProto where show = genericShow
214+type OneofDescriptorProtoR =
183215 { name :: Maybe String -- 1
184216 -- TODO , options :: Maybe OneofOptions -- 2
185217 }
186218
187219-- | Describes an enum type.
188−data EnumDescriptorProto = EnumDescriptorProto
220+newtype EnumDescriptorProto = EnumDescriptorProto EnumDescriptorProtoR
221+derive instance genericEnumDescriptorProto :: Generic EnumDescriptorProto _
222+instance showEnumDescriptorProto :: Show EnumDescriptorProto where show = genericShow
223+type EnumDescriptorProtoR =
189224 { name :: Maybe String -- 1
190225 , value :: Array EnumValueDescriptorProto -- 2
191226 -- TODO , options :: Maybe EnumOptions -- 3
@@ -194,7 +229,10 @@ data EnumDescriptorProto = EnumDescriptorProto
194229 }
195230
196231-- | Describes a value within an enum.
197−data EnumValueDescriptorProto = EnumValueDescriptorProto
232+newtype EnumValueDescriptorProto = EnumValueDescriptorProto EnumValueDescriptorProtoR
233+derive instance genericEnumValueDescriptorProto :: Generic EnumValueDescriptorProto _
234+instance showEnumValueDescriptorProto :: Show EnumValueDescriptorProto where show = genericShow
235+type EnumValueDescriptorProtoR =
198236 { name :: Maybe String -- 1
199237 , number :: Maybe Int -- 2
200238 -- TODO , options :: Maybe EnumValueOptions -- 3
test/test.protonew file+5
@@ -0,0 +1,5 @@
1+syntax = "proto3";
2+
3+message Test2 {
4+ string b = 2;
5+}