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

Support an integer type annotation argument #267

Merged
merged 5 commits into from
May 12, 2018
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
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@ To be released.
import types (country);
~~~~~~~~

- Added support for integer type annotation argument. [[#178], [#267]]

~~~~~~~~ nirum
service foo-service (
@bar(baz=1)
int32 qux (int32 quux),
);
~~~~~~~~

### Docs target

Expand Down Expand Up @@ -187,6 +195,7 @@ To be released.

[#13]: https://github.com/spoqa/nirum/issues/13
[#100]: https://github.com/spoqa/nirum/issues/100
[#178]: https://github.com/spoqa/nirum/issues/178
[#217]: https://github.com/spoqa/nirum/issues/217
[#220]: https://github.com/spoqa/nirum/issues/220
[#227]: https://github.com/spoqa/nirum/pull/227
Expand All @@ -196,6 +205,7 @@ To be released.
[#257]: https://github.com/spoqa/nirum/pull/257
[#258]: https://github.com/spoqa/nirum/pull/258
[#259]: https://github.com/spoqa/nirum/pull/259
[#267]: https://github.com/spoqa/nirum/pull/267
[#269]: https://github.com/spoqa/nirum/pull/269
[entry points]: https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
[python2-numbers-integral]: https://docs.python.org/2/library/numbers.html#numbers.Integral
Expand Down
10 changes: 6 additions & 4 deletions src/Nirum/Constructs/Annotation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import Nirum.Constructs.Annotation.Internal
import Nirum.Constructs.Docs
import Nirum.Constructs.Identifier (Identifier)


docs :: Docs -> Annotation
docs (Docs d) = Annotation { name = docsAnnotationName
, arguments = M.singleton docsAnnotationParameter d
, arguments =
M.singleton docsAnnotationParameter $ Text d
}

newtype NameDuplication = AnnotationNameDuplication Identifier
Expand Down Expand Up @@ -79,7 +79,9 @@ lookupDocs :: AnnotationSet -> Maybe Docs
lookupDocs annotationSet = do
Annotation _ args <- lookup docsAnnotationName annotationSet
d <- M.lookup docsAnnotationParameter args
return $ Docs d
case d of
Text d' -> Just $ Docs d'
_ -> Nothing

insertDocs :: (Monad m) => Docs -> AnnotationSet -> m AnnotationSet
insertDocs docs' (AnnotationSet anno) =
Expand All @@ -90,4 +92,4 @@ insertDocs docs' (AnnotationSet anno) =
insertLookup :: Ord k => k -> a -> M.Map k a -> (Maybe a, M.Map k a)
insertLookup = M.insertLookupWithKey $ \ _ a _ -> a
args :: AnnotationArgumentSet
args = M.singleton docsAnnotationParameter $ toText docs'
args = M.singleton docsAnnotationParameter $ Text $ toText docs'
18 changes: 14 additions & 4 deletions src/Nirum/Constructs/Annotation/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ module Nirum.Constructs.Annotation.Internal
, arguments
, name
)
, AnnotationArgument ( Text
, Integer
)
, AnnotationArgumentSet
, AnnotationSet ( AnnotationSet
, annotations
Expand All @@ -20,7 +23,11 @@ import Nirum.Constructs (Construct (toCode))
import Nirum.Constructs.Docs
import Nirum.Constructs.Identifier (Identifier)

type AnnotationArgumentSet = M.Map Identifier T.Text
data AnnotationArgument = Text T.Text
| Integer Integer
deriving (Eq, Ord, Show)

type AnnotationArgumentSet = M.Map Identifier AnnotationArgument

-- | Annotation for 'Declaration'.
data Annotation = Annotation { name :: Identifier
Expand All @@ -32,10 +39,13 @@ instance Construct Annotation where
| M.null args = '@' `T.cons` toCode n
| otherwise = [qq|@{toCode n}({showArgs $ M.toList args})|]
where
showArgs :: [(Identifier, T.Text)] -> T.Text
showArgs :: [(Identifier, AnnotationArgument)] -> T.Text
showArgs args' = T.intercalate ", " $ map showArg args'
showArg :: (Identifier, T.Text) -> T.Text
showArg (key, value) = [qq|{toCode key} = {literal value}|]
showArg :: (Identifier, AnnotationArgument) -> T.Text
showArg (key, value) = [qq|{toCode key} = {argToText value}|]
argToText :: AnnotationArgument -> T.Text
argToText (Text t) = literal t
argToText (Integer i) = T.pack $ show i
literal :: T.Text -> T.Text
literal s = [qq|"{(showLitString $ T.unpack s) ""}"|]
showLitString :: String -> ShowS
Expand Down
8 changes: 4 additions & 4 deletions src/Nirum/Constructs/Docs.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module Nirum.Constructs.Docs ( Docs (Docs)
, docsAnnotationName
, docsAnnotationParameter
, docsAnnotationName
, title
, toBlock
, toCode
Expand All @@ -17,12 +17,12 @@ import Nirum.Constructs (Construct (toCode))
import Nirum.Constructs.Identifier (Identifier)
import Nirum.Docs (Block (Document, Heading), parse)

docsAnnotationName :: Identifier
docsAnnotationName = "docs"

docsAnnotationParameter :: Identifier
docsAnnotationParameter = "docs"

docsAnnotationName :: Identifier
docsAnnotationName = "docs"

-- | Docstring for constructs.
newtype Docs = Docs T.Text deriving (Eq, Ord, Show)

Expand Down
30 changes: 25 additions & 5 deletions src/Nirum/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Text.Megaparsec hiding (ParseError, parse)
import Text.Megaparsec.Char ( char
, digitChar
, eol
, noneOf
, spaceChar
Expand All @@ -52,8 +53,14 @@ import Text.Megaparsec.Char ( char
)
import qualified Text.Megaparsec.Error as E
import Text.Megaparsec.Char.Lexer (charLiteral)
import Text.Read hiding (choice)

import qualified Nirum.Constructs.Annotation as A
import Nirum.Constructs.Annotation.Internal hiding ( Text
, annotations
, name
)
import qualified Nirum.Constructs.Annotation.Internal as AI
import Nirum.Constructs.Declaration (Declaration)
import qualified Nirum.Constructs.Declaration as D
import Nirum.Constructs.Docs (Docs (Docs))
Expand Down Expand Up @@ -162,13 +169,26 @@ uniqueName forwardNames label' = try $ do
nameP :: Parser Name
nameP = name <?> label'

annotationArgumentValue :: Parser T.Text
integer :: Parser Integer
integer = do
v <- many digitChar
case readMaybe v of
Just i -> return i
Nothing -> fail "digit expected." -- never happened


annotationArgumentValue :: Parser AnnotationArgument
annotationArgumentValue = do
char '"'
value <- manyTill charLiteral (char '"')
return $ T.pack value
startQuote <- optional $ try $ char '"'
case startQuote of
Just _ -> do
v <- manyTill charLiteral (char '"')
return $ AI.Text $ T.pack v
Nothing -> do
v <- integer
return $ Integer v

annotationArgument :: Parser (Identifier, T.Text)
annotationArgument :: Parser (Identifier, AnnotationArgument)
annotationArgument = do
arg <- identifier <?> "annotation parameter"
spaces
Expand Down
10 changes: 6 additions & 4 deletions src/Nirum/Targets/Python.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import Text.Heterocephalus (compileText)
import Text.InterpolatedString.Perl6 (q, qq)

import qualified Nirum.Constructs.Annotation as A
import Nirum.Constructs.Annotation.Internal hiding (Text, annotations, name)
import qualified Nirum.Constructs.Annotation.Internal as AI
import qualified Nirum.Constructs.DeclarationSet as DS
import qualified Nirum.Constructs.Identifier as I
import Nirum.Constructs.Declaration (Documented (docsBlock))
Expand Down Expand Up @@ -1198,15 +1200,15 @@ if hasattr({className}.Client, '__qualname__'):
compileAnnotation ident annoArgument =
toKeyItem ident $
wrapMap $ T.intercalate ","
[ toKeyStr ident' value :: T.Text
[ [qq|'{toAttributeName ident'}': {annoArgToText value}|]
| (ident', value) <- M.toList annoArgument
]
where
escapeSingle :: T.Text -> T.Text
escapeSingle = T.strip . T.replace "'" "\\'"
toKeyStr :: I.Identifier -> T.Text -> T.Text
toKeyStr k v =
[qq|'{toAttributeName k}': u'''{escapeSingle v}'''|]
annoArgToText :: AnnotationArgument -> T.Text
annoArgToText (AI.Text t) = [qq|u'''{escapeSingle t}'''|]
annoArgToText (Integer i) = T.pack $ show i
compileMethodAnnotation :: Method -> T.Text
compileMethodAnnotation Method { methodName = mName
, methodAnnotations = annoSet
Expand Down
25 changes: 13 additions & 12 deletions test/Nirum/Constructs/AnnotationSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import Test.Hspec.Meta
import qualified Data.Map.Strict as M

import Nirum.Constructs.Annotation as A
import Nirum.Constructs.Annotation.Internal ( AnnotationSet (AnnotationSet) )
import Nirum.Constructs.Annotation.Internal

spec :: Spec
spec = do
let annotation = Annotation "foo" M.empty
loremAnno = Annotation "lorem" [("arg", "ipsum")]
escapeCharAnno = Annotation "quote" [("arg", "\"")]
longNameAnno = Annotation "long-cat-is-long" [("long", "nyancat")]
loremAnno = Annotation "lorem" [("arg", Text "ipsum")]
escapeCharAnno = Annotation "quote" [("arg", Text "\"")]
longNameAnno =
Annotation "long-cat-is-long" [("long", Text "nyancat")]
docsAnno = docs "Description"
describe "Annotation" $ do
describe "toCode Annotation" $
Expand All @@ -24,15 +25,15 @@ spec = do
toCode escapeCharAnno `shouldBe` "@quote(arg = \"\\\"\")"
specify "docs" $
docsAnno `shouldBe`
Annotation "docs" [("docs", "Description\n")]
Annotation "docs" [("docs", Text "Description\n")]
describe "AnnotationSet" $ do
specify "empty" $
empty `shouldSatisfy` null
specify "singleton" $ do
singleton (Annotation "foo" []) `shouldBe`
AnnotationSet [("foo", [])]
singleton (Annotation "bar" [("arg", "baz")]) `shouldBe`
AnnotationSet [("bar", [("arg", "baz")])]
singleton (Annotation "bar" [("arg", Text "baz")]) `shouldBe`
AnnotationSet [("bar", [("arg", Text "baz")])]
describe "fromList" $ do
it "success" $ do
let Right empty' = fromList []
Expand All @@ -49,12 +50,12 @@ spec = do
specify "union" $ do
let Right a = fromList [annotation, loremAnno]
let Right b = fromList [docsAnno, escapeCharAnno]
let c = AnnotationSet [("foo", [("arg", "bar")])]
let c = AnnotationSet [("foo", [("arg", Text "bar")])]
A.union a b `shouldBe`
AnnotationSet [ ("foo", [])
, ("lorem", [("arg", "ipsum")])
, ("quote", [("arg", "\"")])
, ("docs", [("docs", "Description\n")])
, ("lorem", [("arg", Text "ipsum")])
, ("quote", [("arg", Text "\"")])
, ("docs", [("docs", Text "Description\n")])
]
A.union a c `shouldBe` a
let Right annotationSet = fromList [ annotation
Expand Down Expand Up @@ -85,6 +86,6 @@ spec = do
describe "insertDocs" $ do
it "should insert the doc comment as an annotation" $
A.insertDocs "yay" empty `shouldReturn`
AnnotationSet [("docs", [("docs", "yay\n")])]
AnnotationSet [("docs", [("docs", Text "yay\n")])]
it "should fail on the annotation that already have a doc" $
A.insertDocs "yay" annotationSet `shouldThrow` anyException
5 changes: 3 additions & 2 deletions test/Nirum/Constructs/ServiceSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Data.Map.Strict as Map (fromList)
import Test.Hspec.Meta

import Nirum.Constructs.Annotation
import Nirum.Constructs.Annotation.Internal
import Nirum.Constructs.Docs (toCode)
import Nirum.Constructs.Service (Method (Method), Parameter (Parameter))
import Nirum.Constructs.TypeExpression ( TypeExpression ( ListModifier
Expand All @@ -18,8 +19,8 @@ import Util (singleDocs)
spec :: Spec
spec = do
let methodAnno = singleton $ Annotation "http" $ Map.fromList
[ ("method", "GET")
, ("path", "/ping/")
[ ("method", Text "GET")
, ("path", Text "/ping/")
]
let docsAnno = singleDocs "docs..."
describe "Parameter" $
Expand Down
3 changes: 2 additions & 1 deletion test/Nirum/Constructs/TypeDeclarationSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Test.Hspec.Meta

import Nirum.Constructs (Construct (toCode))
import Nirum.Constructs.Annotation hiding (docs, fromList, name)
import qualified Nirum.Constructs.Annotation.Internal as AI
import Nirum.Constructs.Declaration (Declaration (name), docs)
import Nirum.Constructs.DeclarationSet hiding (empty)
import Nirum.Constructs.Service (Method (Method), Service (Service))
Expand All @@ -23,7 +24,7 @@ import Nirum.Constructs.TypeDeclaration ( EnumMember (EnumMember)
import Util (singleDocs)

barAnnotationSet :: AnnotationSet
barAnnotationSet = singleton $ Annotation "bar" [("val", "baz")]
barAnnotationSet = singleton $ Annotation "bar" [("val", AI.Text "baz")]

spec :: Spec
spec = do
Expand Down
21 changes: 15 additions & 6 deletions test/Nirum/ParserSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import qualified Nirum.Parser as P
import Nirum.Parser (Parser, ParseError)
import Nirum.Constructs (Construct (toCode))
import Nirum.Constructs.Annotation as A
import Nirum.Constructs.Annotation.Internal hiding (Text)
import qualified Nirum.Constructs.Annotation.Internal as AI
import Nirum.Constructs.Docs (Docs (Docs))
import Nirum.Constructs.DeclarationSet (DeclarationSet)
import Nirum.Constructs.DeclarationSetSpec (SampleDecl (..))
Expand Down Expand Up @@ -80,7 +82,7 @@ helperFuncs parser =


fooAnnotationSet :: AnnotationSet
fooAnnotationSet = A.singleton $ Annotation "foo" [("v", "bar")]
fooAnnotationSet = A.singleton $ Annotation "foo" [("v", AI.Text "bar")]

bazAnnotationSet :: AnnotationSet
bazAnnotationSet = A.singleton $ Annotation "baz" []
Expand Down Expand Up @@ -177,7 +179,10 @@ spec = do
describe "annotation" $ do
let (parse', expectError) = helperFuncs P.annotation
context "with single argument" $ do
let rightAnnotaiton = Annotation "name-abc" [("foo", "wo\"rld")]
let rightAnnotaiton =
Annotation "name-abc" [("foo", AI.Text "wo\"rld")]
let rightIntAnnotation =
Annotation "name-abc" [("foo", Integer 1)]
it "success" $ do
parse' "@name-abc(foo=\"wo\\\"rld\")"
`shouldBeRight` rightAnnotaiton
Expand All @@ -192,7 +197,11 @@ spec = do
parse' "@name-abc ( foo=\"wo\\\"rld\")"
`shouldBeRight` rightAnnotaiton
parse' "@name-abc(foo=\"wo\\\"rld\\n\")" `shouldBeRight`
Annotation "name-abc" [("foo", "wo\"rld\n")]
Annotation "name-abc" [("foo", AI.Text "wo\"rld\n")]
parse' "@name-abc(foo=1)" `shouldBeRight` rightIntAnnotation
parse' "@name-abc( foo=1)" `shouldBeRight` rightIntAnnotation
parse' "@name-abc(foo=1 )" `shouldBeRight` rightIntAnnotation
parse' "@name-abc( foo=1 )" `shouldBeRight` rightIntAnnotation
it "fails to parse if annotation name start with hyphen" $ do
expectError "@-abc(v=\"helloworld\")" 1 2
expectError "@-abc-d(v = \"helloworld\")" 1 2
Expand All @@ -218,7 +227,7 @@ spec = do
describe "annotationSet" $ do
let (parse', expectError) = helperFuncs P.annotationSet
Right annotationSet = fromList
[ Annotation "a" [("arg", "b")]
[ Annotation "a" [("arg", AI.Text "b")]
, Annotation "c" []
]
it "success" $ do
Expand Down Expand Up @@ -822,8 +831,8 @@ union shape
describe "method" $ do
let (parse', expectError) = helperFuncs P.method
httpGetAnnotation = singleton $ Annotation "http"
[ ("method", "GET")
, ("path", "/get-name/")
[ ("method", AI.Text "GET")
, ("path", AI.Text "/get-name/")
]
it "emits Method if succeeded to parse" $ do
parse' "text get-name()" `shouldBeRight`
Expand Down
4 changes: 4 additions & 0 deletions test/nirum_fixture/fixture/datetime.nrm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
service datetime-service (
@num-constraints(min=1, max=12)
int32 delta_month(int32 month),
);
11 changes: 9 additions & 2 deletions test/python/annotation_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from fixture.datetime import DatetimeService
from fixture.foo import PingService, RpcError
from nirum.datastructures import Map

Expand All @@ -11,6 +12,12 @@ def test_service_method_annotation_metadata():
'docs': Map({'docs': u'Method docs.'}),
'http_resource': Map({'method': u'GET', 'path': u'/ping'}),
'quote': Map({'single': u"'", 'triple': u"'''"}),
'unicode': Map({'unicode': u'\uc720\ub2c8\ucf54\ub4dc'}),
})
'unicode': Map({'unicode': u'\uc720\ub2c8\ucf54\ub4dc'}), })
assert PingService.__nirum_method_annotations__['ping'] == expect


def test_annotation_int():
exp = Map({
'num_constraints': Map({'max': 12, 'min': 1}),
})
assert DatetimeService.__nirum_method_annotations__['delta_month'] == exp
Loading