Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement decimal parser 🔢 #1

Merged
merged 8 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions .github/workflows/haskell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,19 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
ghc: ["8.8.1"]
ghc: ["8.8.2"]
cabal: ["3.0"]
steps:
- uses: actions/checkout@v1
- uses: actions/setup-haskell@v1
with:
ghc-version: ${{ matrix.ghc }}
cabal-version: ${{ matrix.cabal }}
# We cache the elements of the Cabal store separately,
# as the entirety of ~/.cabal can grow very large
# for projects with many dependencies.
- uses: actions/cache@v1
name: Cache ~/.cabal/packages
with:
path: ~/.cabal/packages
key: ${{ runner.os }}-${{ matrix.ghc }}-cabal-packages
- uses: actions/cache@v1
name: Cache ~/.cabal/store
with:
path: ~/.cabal/store
key: ${{ runner.os }}-${{ matrix.ghc }}-cabal-store
- uses: actions/cache@v1
name: Cache dist-newstyle
with:
path: dist-newstyle
key: ${{ runner.os }}-${{ matrix.ghc }}-dist-newstyle
- name: Install dependencies
run: |
cabal new-update
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.stack-work
dist*
*.yaml.lock
6 changes: 6 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
packages: .

source-repository-package
type: git
location: https://github.com/serras/avro.git
tag: c684139b773c296079a2941fb30ee43a52b66204
2 changes: 1 addition & 1 deletion language-avro.cabal
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: language-avro
version: 0.1.0.0
version: 0.1.1.0
synopsis: Language definition and parser for AVRO files.
description: Parser for the AVRO language specification, see README.md for more details.
homepage: https://github.com/kutyel/avro-parser-haskell#readme
Expand Down
21 changes: 17 additions & 4 deletions src/Language/Avro/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module Language.Avro.Parser
-- * Intermediate parsers
parseAliases,
parseAnnotation,
parseDecimal,
parseImport,
parseMethod,
parseNamespace,
Expand Down Expand Up @@ -183,17 +184,28 @@ parseMethod =
<*> option False (True <$ reserved "oneway")
<* symbol ";"

-- | Parses the special type @decimal@ into it's corresponding 'Decimal' structure.
parseDecimal :: MonadParsec Char T.Text m => m Decimal
parseDecimal = toDec <$ reserved "decimal" <*> parens (lexeme $ sepBy1 number $ symbol ",")
where
toDec :: [Int] -> Decimal
toDec [precision] = Decimal (fromIntegral precision) 0
toDec [precision, scale] = Decimal (fromIntegral precision) (fromIntegral scale)
toDec _ = error "decimal types can only be specified using two numbers!"

-- | Parses a single type respecting @Data.Avro.Schema@'s 'Schema'.
parseSchema :: MonadParsec Char T.Text m => m Schema
parseSchema =
Null <$ (reserved "null" <|> reserved "void")
<|> Boolean <$ reserved "boolean"
<|> Int <$ reserved "int"
<|> Long <$ reserved "long"
<|> Int' <$ reserved "int"
<|> Long' <$ reserved "long"
<|> Long . Just . DecimalL <$> parseDecimal
<|> Float <$ reserved "float"
<|> Double <$ reserved "double"
<|> Bytes <$ reserved "bytes"
<|> String <$ reserved "string"
<|> Bytes' <$ reserved "bytes"
<|> String (Just UUID) <$ reserved "uuid"
<|> String' <$ reserved "string"
<|> Array <$ reserved "array" <*> diamonds parseSchema
<|> Map <$ reserved "map" <*> diamonds parseSchema
<|> Union <$ reserved "union" <*> parseVector parseSchema
Expand All @@ -202,6 +214,7 @@ parseSchema =
<$> option [] parseAliases <* reserved "fixed"
<*> parseTypeName
<*> parens number
<*> pure Nothing
)
<|> try
( flip Enum
Expand Down
7 changes: 7 additions & 0 deletions stack-nightly.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
resolver: nightly-2020-02-14
packages:
- .
extra-deps:
- HasBigDecimal-0.1.1
- git: https://github.com/serras/avro.git
commit: c684139b773c296079a2941fb30ee43a52b66204
6 changes: 5 additions & 1 deletion stack.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
resolver: lts-14.20
resolver: lts-14.25
packages:
- .
extra-deps:
- HasBigDecimal-0.1.1
- git: https://github.com/serras/avro.git
commit: c684139b773c296079a2941fb30ee43a52b66204
12 changes: 0 additions & 12 deletions stack.yaml.lock

This file was deleted.

41 changes: 23 additions & 18 deletions test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,33 +95,38 @@ main = hspec $ do
it "should parse boolean" $
parse parseSchema "" "boolean" `shouldBe` Right Boolean
it "should parse int" $
parse parseSchema "" "int" `shouldBe` Right Int
parse parseSchema "" "int" `shouldBe` Right Int'
it "should parse long" $
parse parseSchema "" "long" `shouldBe` Right Long
parse parseSchema "" "long" `shouldBe` Right Long'
it "should parse float" $
parse parseSchema "" "float" `shouldBe` Right Float
it "should parse double" $
parse parseSchema "" "double" `shouldBe` Right Double
it "should parse decimal" $ do
parse parseDecimal "" "decimal(4)" `shouldBe` (Right $ Decimal 4 0)
parse parseDecimal "" "decimal(15,2)" `shouldBe` (Right $ Decimal 15 2)
it "should parse bytes" $
parse parseSchema "" "bytes" `shouldBe` Right Bytes
parse parseSchema "" "bytes" `shouldBe` Right Bytes'
it "should parse string" $
parse parseSchema "" "string" `shouldBe` Right String
parse parseSchema "" "string" `shouldBe` Right String'
it "should parse uuid" $
parse parseSchema "" "uuid" `shouldBe` Right (String (Just UUID))
it "should parse array" $ do
parse parseSchema "" "array<int>" `shouldBe` (Right $ Array Int)
parse parseSchema "" "array<int>" `shouldBe` (Right $ Array Int')
parse parseSchema "" "array<array<string>>"
`shouldBe` (Right $ Array $ Array String)
`shouldBe` (Right $ Array $ Array String')
it "should parse map" $ do
parse parseSchema "" "map<int>" `shouldBe` (Right $ Map Int)
parse parseSchema "" "map<int>" `shouldBe` (Right $ Map Int')
parse parseSchema "" "map<map<string>>"
`shouldBe` (Right $ Map $ Map String)
`shouldBe` (Right $ Map $ Map String')
it "should parse unions" $
parse parseSchema "" "union { string, int, null }"
`shouldBe` (Right $ Union $ fromList [String, Int, Null])
`shouldBe` (Right $ Union $ fromList [String', Int', Null])
it "should parse fixeds" $ do
parse parseSchema "" "fixed MD5(16)"
`shouldBe` (Right $ Fixed (TN "MD5" []) [] 16)
`shouldBe` (Right $ Fixed (TN "MD5" []) [] 16 Nothing)
parse parseSchema "" "@aliases([\"org.foo.MD5\"])\nfixed MD5(16)"
`shouldBe` (Right $ Fixed (TN "MD5" []) ["org.foo.MD5"] 16)
`shouldBe` (Right $ Fixed (TN "MD5" []) ["org.foo.MD5"] 16 Nothing)
it "should parse enums" $ do
parse parseSchema "" enumTest
`shouldBe` (Right $ Enum (TN "Kind" []) [TN "KindOf" ["org", "foo"]] Nothing (fromList ["FOO", "BAR", "BAZ"]))
Expand All @@ -143,8 +148,8 @@ main = hspec $ do
[TN "Person" ["org", "foo"]]
Nothing -- docs are ignored for now...
Nothing -- order is ignored for now...
[ Field "name" [] Nothing Nothing String Nothing,
Field "age" [] Nothing Nothing Int Nothing
[ Field "name" [] Nothing Nothing String' Nothing,
Field "age" [] Nothing Nothing Int' Nothing
]
)
it "should parse complex records" $
Expand All @@ -155,11 +160,11 @@ main = hspec $ do
[]
Nothing -- docs are ignored for now...
Nothing -- order is ignored for now...
[ Field "name" [] Nothing (Just Ignore) String Nothing,
[ Field "name" [] Nothing (Just Ignore) String' Nothing,
Field "kind" [] Nothing (Just Descending) (NamedType "Kind") Nothing,
Field "hash" [] Nothing Nothing (NamedType "MD5") Nothing,
Field "nullableHash" ["hash"] Nothing Nothing (Union $ fromList [NamedType "MD5", Null]) Nothing,
Field "arrayOfLongs" [] Nothing Nothing (Array Long) Nothing
Field "arrayOfLongs" [] Nothing Nothing (Array Long') Nothing
]
)
describe "Parse protocols" $ do
Expand Down Expand Up @@ -193,17 +198,17 @@ main = hspec $ do
describe "Parse services" $ do
it "should parse simple messages" $
parse parseMethod "" "string hello(string greeting);"
`shouldBe` (Right $ Method "hello" [Argument String "greeting"] String Null False)
`shouldBe` (Right $ Method "hello" [Argument String' "greeting"] String' Null False)
it "should parse more simple messages" $
parse parseMethod "" "bytes echoBytes(bytes data);"
`shouldBe` (Right $ Method "echoBytes" [Argument Bytes "data"] Bytes Null False)
`shouldBe` (Right $ Method "echoBytes" [Argument Bytes' "data"] Bytes' Null False)
it "should parse custom type messages" $
let custom = NamedType "TestRecord"
in parse parseMethod "" "TestRecord echo(TestRecord `record`);"
`shouldBe` (Right $ Method "echo" [Argument custom "record"] custom Null False)
it "should parse multiple argument messages" $
parse parseMethod "" "int add(int arg1, int arg2);"
`shouldBe` (Right $ Method "add" [Argument Int "arg1", Argument Int "arg2"] Int Null False)
`shouldBe` (Right $ Method "add" [Argument Int' "arg1", Argument Int' "arg2"] Int' Null False)
it "should parse escaped and throwing messages" $
parse parseMethod "" "void `error`() throws TestError;"
`shouldBe` (Right $ Method "error" [] Null (NamedType $ TN "TestError" []) False)
Expand Down