Skip to content

Commit 5633ee0

Browse files
authored
Merge pull request #267 from admire93/annotation-integer
Support an integer type annotation argument
2 parents 814f455 + e1498ef commit 5633ee0

File tree

13 files changed

+113
-44
lines changed

13 files changed

+113
-44
lines changed

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ To be released.
126126
import types (country);
127127
~~~~~~~~
128128
129+
- Added support for integer type annotation argument. [[#178], [#267]]
130+
131+
~~~~~~~~ nirum
132+
service foo-service (
133+
@bar(baz=1)
134+
int32 qux (int32 quux),
135+
);
136+
~~~~~~~~
129137
130138
### Docs target
131139
@@ -187,6 +195,7 @@ To be released.
187195
188196
[#13]: https://github.com/spoqa/nirum/issues/13
189197
[#100]: https://github.com/spoqa/nirum/issues/100
198+
[#178]: https://github.com/spoqa/nirum/issues/178
190199
[#217]: https://github.com/spoqa/nirum/issues/217
191200
[#220]: https://github.com/spoqa/nirum/issues/220
192201
[#227]: https://github.com/spoqa/nirum/pull/227
@@ -196,6 +205,7 @@ To be released.
196205
[#257]: https://github.com/spoqa/nirum/pull/257
197206
[#258]: https://github.com/spoqa/nirum/pull/258
198207
[#259]: https://github.com/spoqa/nirum/pull/259
208+
[#267]: https://github.com/spoqa/nirum/pull/267
199209
[#269]: https://github.com/spoqa/nirum/pull/269
200210
[entry points]: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
201211
[python2-numbers-integral]: https://docs.python.org/2/library/numbers.html#numbers.Integral

src/Nirum/Constructs/Annotation.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import Nirum.Constructs.Annotation.Internal
2727
import Nirum.Constructs.Docs
2828
import Nirum.Constructs.Identifier (Identifier)
2929

30-
3130
docs :: Docs -> Annotation
3231
docs (Docs d) = Annotation { name = docsAnnotationName
33-
, arguments = M.singleton docsAnnotationParameter d
32+
, arguments =
33+
M.singleton docsAnnotationParameter $ Text d
3434
}
3535

3636
newtype NameDuplication = AnnotationNameDuplication Identifier
@@ -79,7 +79,9 @@ lookupDocs :: AnnotationSet -> Maybe Docs
7979
lookupDocs annotationSet = do
8080
Annotation _ args <- lookup docsAnnotationName annotationSet
8181
d <- M.lookup docsAnnotationParameter args
82-
return $ Docs d
82+
case d of
83+
Text d' -> Just $ Docs d'
84+
_ -> Nothing
8385

8486
insertDocs :: (Monad m) => Docs -> AnnotationSet -> m AnnotationSet
8587
insertDocs docs' (AnnotationSet anno) =
@@ -90,4 +92,4 @@ insertDocs docs' (AnnotationSet anno) =
9092
insertLookup :: Ord k => k -> a -> M.Map k a -> (Maybe a, M.Map k a)
9193
insertLookup = M.insertLookupWithKey $ \ _ a _ -> a
9294
args :: AnnotationArgumentSet
93-
args = M.singleton docsAnnotationParameter $ toText docs'
95+
args = M.singleton docsAnnotationParameter $ Text $ toText docs'

src/Nirum/Constructs/Annotation/Internal.hs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ module Nirum.Constructs.Annotation.Internal
44
, arguments
55
, name
66
)
7+
, AnnotationArgument ( Text
8+
, Integer
9+
)
710
, AnnotationArgumentSet
811
, AnnotationSet ( AnnotationSet
912
, annotations
@@ -20,7 +23,11 @@ import Nirum.Constructs (Construct (toCode))
2023
import Nirum.Constructs.Docs
2124
import Nirum.Constructs.Identifier (Identifier)
2225

23-
type AnnotationArgumentSet = M.Map Identifier T.Text
26+
data AnnotationArgument = Text T.Text
27+
| Integer Integer
28+
deriving (Eq, Ord, Show)
29+
30+
type AnnotationArgumentSet = M.Map Identifier AnnotationArgument
2431

2532
-- | Annotation for 'Declaration'.
2633
data Annotation = Annotation { name :: Identifier
@@ -32,10 +39,13 @@ instance Construct Annotation where
3239
| M.null args = '@' `T.cons` toCode n
3340
| otherwise = [qq|@{toCode n}({showArgs $ M.toList args})|]
3441
where
35-
showArgs :: [(Identifier, T.Text)] -> T.Text
42+
showArgs :: [(Identifier, AnnotationArgument)] -> T.Text
3643
showArgs args' = T.intercalate ", " $ map showArg args'
37-
showArg :: (Identifier, T.Text) -> T.Text
38-
showArg (key, value) = [qq|{toCode key} = {literal value}|]
44+
showArg :: (Identifier, AnnotationArgument) -> T.Text
45+
showArg (key, value) = [qq|{toCode key} = {argToText value}|]
46+
argToText :: AnnotationArgument -> T.Text
47+
argToText (Text t) = literal t
48+
argToText (Integer i) = T.pack $ show i
3949
literal :: T.Text -> T.Text
4050
literal s = [qq|"{(showLitString $ T.unpack s) ""}"|]
4151
showLitString :: String -> ShowS

src/Nirum/Constructs/Docs.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{-# LANGUAGE OverloadedStrings #-}
22
module Nirum.Constructs.Docs ( Docs (Docs)
3-
, docsAnnotationName
43
, docsAnnotationParameter
4+
, docsAnnotationName
55
, title
66
, toBlock
77
, toCode
@@ -17,12 +17,12 @@ import Nirum.Constructs (Construct (toCode))
1717
import Nirum.Constructs.Identifier (Identifier)
1818
import Nirum.Docs (Block (Document, Heading), parse)
1919

20-
docsAnnotationName :: Identifier
21-
docsAnnotationName = "docs"
22-
2320
docsAnnotationParameter :: Identifier
2421
docsAnnotationParameter = "docs"
2522

23+
docsAnnotationName :: Identifier
24+
docsAnnotationName = "docs"
25+
2626
-- | Docstring for constructs.
2727
newtype Docs = Docs T.Text deriving (Eq, Ord, Show)
2828

src/Nirum/Parser.hs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import qualified Data.Text as T
4444
import qualified Data.Text.IO as TIO
4545
import Text.Megaparsec hiding (ParseError, parse)
4646
import Text.Megaparsec.Char ( char
47+
, digitChar
4748
, eol
4849
, noneOf
4950
, spaceChar
@@ -52,8 +53,14 @@ import Text.Megaparsec.Char ( char
5253
)
5354
import qualified Text.Megaparsec.Error as E
5455
import Text.Megaparsec.Char.Lexer (charLiteral)
56+
import Text.Read hiding (choice)
5557

5658
import qualified Nirum.Constructs.Annotation as A
59+
import Nirum.Constructs.Annotation.Internal hiding ( Text
60+
, annotations
61+
, name
62+
)
63+
import qualified Nirum.Constructs.Annotation.Internal as AI
5764
import Nirum.Constructs.Declaration (Declaration)
5865
import qualified Nirum.Constructs.Declaration as D
5966
import Nirum.Constructs.Docs (Docs (Docs))
@@ -162,13 +169,26 @@ uniqueName forwardNames label' = try $ do
162169
nameP :: Parser Name
163170
nameP = name <?> label'
164171

165-
annotationArgumentValue :: Parser T.Text
172+
integer :: Parser Integer
173+
integer = do
174+
v <- many digitChar
175+
case readMaybe v of
176+
Just i -> return i
177+
Nothing -> fail "digit expected." -- never happened
178+
179+
180+
annotationArgumentValue :: Parser AnnotationArgument
166181
annotationArgumentValue = do
167-
char '"'
168-
value <- manyTill charLiteral (char '"')
169-
return $ T.pack value
182+
startQuote <- optional $ try $ char '"'
183+
case startQuote of
184+
Just _ -> do
185+
v <- manyTill charLiteral (char '"')
186+
return $ AI.Text $ T.pack v
187+
Nothing -> do
188+
v <- integer
189+
return $ Integer v
170190

171-
annotationArgument :: Parser (Identifier, T.Text)
191+
annotationArgument :: Parser (Identifier, AnnotationArgument)
172192
annotationArgument = do
173193
arg <- identifier <?> "annotation parameter"
174194
spaces

src/Nirum/Targets/Python.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import Text.Heterocephalus (compileText)
4040
import Text.InterpolatedString.Perl6 (q, qq)
4141

4242
import qualified Nirum.Constructs.Annotation as A
43+
import Nirum.Constructs.Annotation.Internal hiding (Text, annotations, name)
44+
import qualified Nirum.Constructs.Annotation.Internal as AI
4345
import qualified Nirum.Constructs.DeclarationSet as DS
4446
import qualified Nirum.Constructs.Identifier as I
4547
import Nirum.Constructs.Declaration (Documented (docsBlock))
@@ -1198,15 +1200,15 @@ if hasattr({className}.Client, '__qualname__'):
11981200
compileAnnotation ident annoArgument =
11991201
toKeyItem ident $
12001202
wrapMap $ T.intercalate ","
1201-
[ toKeyStr ident' value :: T.Text
1203+
[ [qq|'{toAttributeName ident'}': {annoArgToText value}|]
12021204
| (ident', value) <- M.toList annoArgument
12031205
]
12041206
where
12051207
escapeSingle :: T.Text -> T.Text
12061208
escapeSingle = T.strip . T.replace "'" "\\'"
1207-
toKeyStr :: I.Identifier -> T.Text -> T.Text
1208-
toKeyStr k v =
1209-
[qq|'{toAttributeName k}': u'''{escapeSingle v}'''|]
1209+
annoArgToText :: AnnotationArgument -> T.Text
1210+
annoArgToText (AI.Text t) = [qq|u'''{escapeSingle t}'''|]
1211+
annoArgToText (Integer i) = T.pack $ show i
12101212
compileMethodAnnotation :: Method -> T.Text
12111213
compileMethodAnnotation Method { methodName = mName
12121214
, methodAnnotations = annoSet

test/Nirum/Constructs/AnnotationSpec.hs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ import Test.Hspec.Meta
77
import qualified Data.Map.Strict as M
88

99
import Nirum.Constructs.Annotation as A
10-
import Nirum.Constructs.Annotation.Internal ( AnnotationSet (AnnotationSet) )
10+
import Nirum.Constructs.Annotation.Internal
1111

1212
spec :: Spec
1313
spec = do
1414
let annotation = Annotation "foo" M.empty
15-
loremAnno = Annotation "lorem" [("arg", "ipsum")]
16-
escapeCharAnno = Annotation "quote" [("arg", "\"")]
17-
longNameAnno = Annotation "long-cat-is-long" [("long", "nyancat")]
15+
loremAnno = Annotation "lorem" [("arg", Text "ipsum")]
16+
escapeCharAnno = Annotation "quote" [("arg", Text "\"")]
17+
longNameAnno =
18+
Annotation "long-cat-is-long" [("long", Text "nyancat")]
1819
docsAnno = docs "Description"
1920
describe "Annotation" $ do
2021
describe "toCode Annotation" $
@@ -24,15 +25,15 @@ spec = do
2425
toCode escapeCharAnno `shouldBe` "@quote(arg = \"\\\"\")"
2526
specify "docs" $
2627
docsAnno `shouldBe`
27-
Annotation "docs" [("docs", "Description\n")]
28+
Annotation "docs" [("docs", Text "Description\n")]
2829
describe "AnnotationSet" $ do
2930
specify "empty" $
3031
empty `shouldSatisfy` null
3132
specify "singleton" $ do
3233
singleton (Annotation "foo" []) `shouldBe`
3334
AnnotationSet [("foo", [])]
34-
singleton (Annotation "bar" [("arg", "baz")]) `shouldBe`
35-
AnnotationSet [("bar", [("arg", "baz")])]
35+
singleton (Annotation "bar" [("arg", Text "baz")]) `shouldBe`
36+
AnnotationSet [("bar", [("arg", Text "baz")])]
3637
describe "fromList" $ do
3738
it "success" $ do
3839
let Right empty' = fromList []
@@ -49,12 +50,12 @@ spec = do
4950
specify "union" $ do
5051
let Right a = fromList [annotation, loremAnno]
5152
let Right b = fromList [docsAnno, escapeCharAnno]
52-
let c = AnnotationSet [("foo", [("arg", "bar")])]
53+
let c = AnnotationSet [("foo", [("arg", Text "bar")])]
5354
A.union a b `shouldBe`
5455
AnnotationSet [ ("foo", [])
55-
, ("lorem", [("arg", "ipsum")])
56-
, ("quote", [("arg", "\"")])
57-
, ("docs", [("docs", "Description\n")])
56+
, ("lorem", [("arg", Text "ipsum")])
57+
, ("quote", [("arg", Text "\"")])
58+
, ("docs", [("docs", Text "Description\n")])
5859
]
5960
A.union a c `shouldBe` a
6061
let Right annotationSet = fromList [ annotation
@@ -85,6 +86,6 @@ spec = do
8586
describe "insertDocs" $ do
8687
it "should insert the doc comment as an annotation" $
8788
A.insertDocs "yay" empty `shouldReturn`
88-
AnnotationSet [("docs", [("docs", "yay\n")])]
89+
AnnotationSet [("docs", [("docs", Text "yay\n")])]
8990
it "should fail on the annotation that already have a doc" $
9091
A.insertDocs "yay" annotationSet `shouldThrow` anyException

test/Nirum/Constructs/ServiceSpec.hs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Data.Map.Strict as Map (fromList)
66
import Test.Hspec.Meta
77

88
import Nirum.Constructs.Annotation
9+
import Nirum.Constructs.Annotation.Internal
910
import Nirum.Constructs.Docs (toCode)
1011
import Nirum.Constructs.Service (Method (Method), Parameter (Parameter))
1112
import Nirum.Constructs.TypeExpression ( TypeExpression ( ListModifier
@@ -18,8 +19,8 @@ import Util (singleDocs)
1819
spec :: Spec
1920
spec = do
2021
let methodAnno = singleton $ Annotation "http" $ Map.fromList
21-
[ ("method", "GET")
22-
, ("path", "/ping/")
22+
[ ("method", Text "GET")
23+
, ("path", Text "/ping/")
2324
]
2425
let docsAnno = singleDocs "docs..."
2526
describe "Parameter" $

test/Nirum/Constructs/TypeDeclarationSpec.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import Test.Hspec.Meta
88

99
import Nirum.Constructs (Construct (toCode))
1010
import Nirum.Constructs.Annotation hiding (docs, fromList, name)
11+
import qualified Nirum.Constructs.Annotation.Internal as AI
1112
import Nirum.Constructs.Declaration (Declaration (name), docs)
1213
import Nirum.Constructs.DeclarationSet hiding (empty)
1314
import Nirum.Constructs.Service (Method (Method), Service (Service))
@@ -23,7 +24,7 @@ import Nirum.Constructs.TypeDeclaration ( EnumMember (EnumMember)
2324
import Util (singleDocs)
2425

2526
barAnnotationSet :: AnnotationSet
26-
barAnnotationSet = singleton $ Annotation "bar" [("val", "baz")]
27+
barAnnotationSet = singleton $ Annotation "bar" [("val", AI.Text "baz")]
2728

2829
spec :: Spec
2930
spec = do

test/Nirum/ParserSpec.hs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import qualified Nirum.Parser as P
2525
import Nirum.Parser (Parser, ParseError)
2626
import Nirum.Constructs (Construct (toCode))
2727
import Nirum.Constructs.Annotation as A
28+
import Nirum.Constructs.Annotation.Internal hiding (Text)
29+
import qualified Nirum.Constructs.Annotation.Internal as AI
2830
import Nirum.Constructs.Docs (Docs (Docs))
2931
import Nirum.Constructs.DeclarationSet (DeclarationSet)
3032
import Nirum.Constructs.DeclarationSetSpec (SampleDecl (..))
@@ -80,7 +82,7 @@ helperFuncs parser =
8082

8183

8284
fooAnnotationSet :: AnnotationSet
83-
fooAnnotationSet = A.singleton $ Annotation "foo" [("v", "bar")]
85+
fooAnnotationSet = A.singleton $ Annotation "foo" [("v", AI.Text "bar")]
8486

8587
bazAnnotationSet :: AnnotationSet
8688
bazAnnotationSet = A.singleton $ Annotation "baz" []
@@ -177,7 +179,10 @@ spec = do
177179
describe "annotation" $ do
178180
let (parse', expectError) = helperFuncs P.annotation
179181
context "with single argument" $ do
180-
let rightAnnotaiton = Annotation "name-abc" [("foo", "wo\"rld")]
182+
let rightAnnotaiton =
183+
Annotation "name-abc" [("foo", AI.Text "wo\"rld")]
184+
let rightIntAnnotation =
185+
Annotation "name-abc" [("foo", Integer 1)]
181186
it "success" $ do
182187
parse' "@name-abc(foo=\"wo\\\"rld\")"
183188
`shouldBeRight` rightAnnotaiton
@@ -192,7 +197,11 @@ spec = do
192197
parse' "@name-abc ( foo=\"wo\\\"rld\")"
193198
`shouldBeRight` rightAnnotaiton
194199
parse' "@name-abc(foo=\"wo\\\"rld\\n\")" `shouldBeRight`
195-
Annotation "name-abc" [("foo", "wo\"rld\n")]
200+
Annotation "name-abc" [("foo", AI.Text "wo\"rld\n")]
201+
parse' "@name-abc(foo=1)" `shouldBeRight` rightIntAnnotation
202+
parse' "@name-abc( foo=1)" `shouldBeRight` rightIntAnnotation
203+
parse' "@name-abc(foo=1 )" `shouldBeRight` rightIntAnnotation
204+
parse' "@name-abc( foo=1 )" `shouldBeRight` rightIntAnnotation
196205
it "fails to parse if annotation name start with hyphen" $ do
197206
expectError "@-abc(v=\"helloworld\")" 1 2
198207
expectError "@-abc-d(v = \"helloworld\")" 1 2
@@ -218,7 +227,7 @@ spec = do
218227
describe "annotationSet" $ do
219228
let (parse', expectError) = helperFuncs P.annotationSet
220229
Right annotationSet = fromList
221-
[ Annotation "a" [("arg", "b")]
230+
[ Annotation "a" [("arg", AI.Text "b")]
222231
, Annotation "c" []
223232
]
224233
it "success" $ do
@@ -822,8 +831,8 @@ union shape
822831
describe "method" $ do
823832
let (parse', expectError) = helperFuncs P.method
824833
httpGetAnnotation = singleton $ Annotation "http"
825-
[ ("method", "GET")
826-
, ("path", "/get-name/")
834+
[ ("method", AI.Text "GET")
835+
, ("path", AI.Text "/get-name/")
827836
]
828837
it "emits Method if succeeded to parse" $ do
829838
parse' "text get-name()" `shouldBeRight`
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
service datetime-service (
2+
@num-constraints(min=1, max=12)
3+
int32 delta_month(int32 month),
4+
);

test/python/annotation_test.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from fixture.datetime import DatetimeService
12
from fixture.foo import PingService, RpcError
23
from nirum.datastructures import Map
34

@@ -11,6 +12,12 @@ def test_service_method_annotation_metadata():
1112
'docs': Map({'docs': u'Method docs.'}),
1213
'http_resource': Map({'method': u'GET', 'path': u'/ping'}),
1314
'quote': Map({'single': u"'", 'triple': u"'''"}),
14-
'unicode': Map({'unicode': u'\uc720\ub2c8\ucf54\ub4dc'}),
15-
})
15+
'unicode': Map({'unicode': u'\uc720\ub2c8\ucf54\ub4dc'}), })
1616
assert PingService.__nirum_method_annotations__['ping'] == expect
17+
18+
19+
def test_annotation_int():
20+
exp = Map({
21+
'num_constraints': Map({'max': 12, 'min': 1}),
22+
})
23+
assert DatetimeService.__nirum_method_annotations__['delta_month'] == exp

0 commit comments

Comments
 (0)