From 36957d2090794efc30d626213134b59218604622 Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sat, 13 Aug 2016 02:39:20 +0900 Subject: [PATCH 1/2] Add syntax to describe error type of service method --- src/Nirum/Constructs/Service.hs | 8 +- src/Nirum/Parser.hs | 9 +- src/Nirum/Targets/Python.hs | 4 +- test/Nirum/Constructs/ServiceSpec.hs | 151 ++++++++++++++++++- test/Nirum/Constructs/TypeDeclarationSpec.hs | 2 +- test/Nirum/ParserSpec.hs | 55 ++++++- test/Nirum/Targets/PythonSpec.hs | 1 + 7 files changed, 214 insertions(+), 16 deletions(-) diff --git a/src/Nirum/Constructs/Service.hs b/src/Nirum/Constructs/Service.hs index e2c2e2d..aeb0b02 100644 --- a/src/Nirum/Constructs/Service.hs +++ b/src/Nirum/Constructs/Service.hs @@ -43,12 +43,14 @@ instance Declaration Parameter where data Method = Method { methodName :: Name , parameters :: DeclarationSet Parameter , returnType :: TypeExpression + , errorType :: Maybe TypeExpression , methodDocs :: Maybe Docs , methodAnnotations :: AnnotationSet } deriving (Eq, Ord, Show) instance Construct Method where toCode method@Method { parameters = params + , errorType = error' , methodDocs = docs' , methodAnnotations = annotationSet' } = @@ -67,7 +69,11 @@ instance Construct Method where , T.intercalate "\n" $ map indentedCode params' , "\n" ] - ++ ["),"] + ++ [")"] + ++ case error' of + Nothing -> [] + Just e -> [" throws ", toCode e] + ++ [","] where params' :: [Parameter] params' = toList params diff --git a/src/Nirum/Parser.hs b/src/Nirum/Parser.hs index 5c661a1..56653f0 100644 --- a/src/Nirum/Parser.hs +++ b/src/Nirum/Parser.hs @@ -452,7 +452,14 @@ method = do params <- parameterSet spaces char ')' - return $ Method methodName params returnType docs' annotationSet' + spaces + errorType <- optional $ do + string "throws" "throws keyword" + spaces + e <- typeExpression "method error type" + spaces + return e + return $ Method methodName params returnType errorType docs' annotationSet' methods :: Parser [Method] methods = method `sepEndBy` try (spaces >> char ',' >> spaces) diff --git a/src/Nirum/Targets/Python.hs b/src/Nirum/Targets/Python.hs index da5bcfa..272068b 100644 --- a/src/Nirum/Targets/Python.hs +++ b/src/Nirum/Targets/Python.hs @@ -515,7 +515,7 @@ class $className(service_type): commaNl :: [T.Text] -> T.Text commaNl = T.intercalate ",\n" compileMethod :: Method -> CodeGen Code - compileMethod (Method mName params rtype _ _) = do + compileMethod (Method mName params rtype _etype _docs _anno) = do let mName' = toAttributeName' mName params' <- mapM compileParameter $ toList params rtypeExpr <- compileTypeExpression src rtype @@ -528,7 +528,7 @@ class $className(service_type): pTypeExpr <- compileTypeExpression src pType return [qq|{toAttributeName' pName}: $pTypeExpr|] compileMethodMetadata :: Method -> CodeGen Code - compileMethodMetadata (Method mName params rtype _ _) = do + compileMethodMetadata (Method mName params rtype _etype _docs _anno) = do let params' = toList params :: [Parameter] rtypeExpr <- compileTypeExpression src rtype paramMetadata <- mapM compileParameterMetadata params' diff --git a/test/Nirum/Constructs/ServiceSpec.hs b/test/Nirum/Constructs/ServiceSpec.hs index 1533ce6..06ee975 100644 --- a/test/Nirum/Constructs/ServiceSpec.hs +++ b/test/Nirum/Constructs/ServiceSpec.hs @@ -22,32 +22,78 @@ spec = do "date dob,\n# docs..." describe "Method" $ specify "toCode" $ do - toCode (Method "ping" [] "bool" Nothing empty) `shouldBe` + toCode (Method "ping" [] "bool" + Nothing + Nothing + empty) `shouldBe` "bool ping ()," - toCode (Method "ping" [] "bool" Nothing methodAnno) `shouldBe` - "[http-get: \"/ping/\"]\nbool ping ()," - toCode (Method "ping" [] "bool" (Just "docs...") empty) `shouldBe` + toCode (Method "ping" [] "bool" + Nothing + (Just "docs...") + empty) `shouldBe` "bool ping (\n # docs...\n)," + toCode (Method "ping" [] "bool" + (Just "ping-error") + Nothing + empty) `shouldBe` + "bool ping () throws ping-error," + toCode (Method "ping" [] "bool" + (Just "ping-error") + (Just "docs...") + empty) `shouldBe` + "bool ping (\n # docs...\n) throws ping-error," + toCode (Method "ping" [] "bool" + Nothing + Nothing + methodAnno) `shouldBe` + "[http-get: \"/ping/\"]\nbool ping ()," + toCode (Method "ping" [] "bool" + (Just "ping-error") + Nothing + methodAnno) `shouldBe` + "[http-get: \"/ping/\"]\nbool ping () throws ping-error," toCode (Method "get-user" [Parameter "user-id" "uuid" Nothing] (OptionModifier "user") Nothing - empty) `shouldBe` "user? get-user (uuid user-id)," + Nothing + empty) `shouldBe` + "user? get-user (uuid user-id)," toCode (Method "get-user" [Parameter "user-id" "uuid" Nothing] (OptionModifier "user") + Nothing (Just "docs...") empty) `shouldBe` "user? get-user (\n # docs...\n uuid user-id,\n)," + toCode (Method "get-user" + [Parameter "user-id" "uuid" Nothing] + (OptionModifier "user") + (Just "get-user-error") + Nothing + empty) `shouldBe` + "user? get-user (uuid user-id) throws get-user-error," + toCode (Method "get-user" + [Parameter "user-id" "uuid" Nothing] + (OptionModifier "user") + (Just "get-user-error") + (Just "docs...") + empty) `shouldBe` + "user? get-user (\n\ + \ # docs...\n\ + \ uuid user-id,\n\ + \) throws get-user-error," toCode (Method "get-user" [Parameter "user-id" "uuid" $ Just "param docs..."] (OptionModifier "user") Nothing + Nothing empty) `shouldBe` "user? get-user (\n uuid user-id,\n # param docs...\n)," toCode (Method "get-user" [Parameter "user-id" "uuid" $ Just "param docs..."] (OptionModifier "user") + Nothing (Just "docs...") empty) `shouldBe` "user? get-user (\n\ @@ -55,12 +101,34 @@ spec = do \ uuid user-id,\n\ \ # param docs...\n\ \)," + toCode (Method "get-user" + [Parameter "user-id" "uuid" $ Just "param docs..."] + (OptionModifier "user") + (Just "get-user-error") + Nothing + empty) `shouldBe` + "user? get-user (\n\ + \ uuid user-id,\n\ + \ # param docs...\n\ + \) throws get-user-error," + toCode (Method "get-user" + [Parameter "user-id" "uuid" $ Just "param docs..."] + (OptionModifier "user") + (Just "get-user-error") + (Just "docs...") + empty) `shouldBe` + "user? get-user (\n\ + \ # docs...\n\ + \ uuid user-id,\n\ + \ # param docs...\n\ + \) throws get-user-error," toCode (Method "search-posts" [ Parameter "blog-id" "uuid" Nothing , Parameter "keyword" "text" Nothing ] (ListModifier "post") Nothing + Nothing empty) `shouldBe` "[post] search-posts (\n uuid blog-id,\n text keyword,\n)," toCode (Method "search-posts" @@ -68,6 +136,7 @@ spec = do , Parameter "keyword" "text" Nothing ] (ListModifier "post") + Nothing (Just "docs...") empty) `shouldBe` "[post] search-posts (\n\ @@ -75,12 +144,38 @@ spec = do \ uuid blog-id,\n\ \ text keyword,\n\ \)," + toCode (Method "search-posts" + [ Parameter "blog-id" "uuid" Nothing + , Parameter "keyword" "text" Nothing + ] + (ListModifier "post") + (Just "search-posts-error") + Nothing + empty) `shouldBe` + "[post] search-posts (\n\ + \ uuid blog-id,\n\ + \ text keyword,\n\ + \) throws search-posts-error," + toCode (Method "search-posts" + [ Parameter "blog-id" "uuid" Nothing + , Parameter "keyword" "text" Nothing + ] + (ListModifier "post") + (Just "search-posts-error") + (Just "docs...") + empty) `shouldBe` + "[post] search-posts (\n\ + \ # docs...\n\ + \ uuid blog-id,\n\ + \ text keyword,\n\ + \) throws search-posts-error," toCode (Method "search-posts" [ Parameter "blog-id" "uuid" $ Just "blog id..." , Parameter "keyword" "text" $ Just "keyword..." ] (ListModifier "post") Nothing + Nothing empty) `shouldBe` "[post] search-posts (\n\ \ uuid blog-id,\n\ @@ -93,6 +188,7 @@ spec = do , Parameter "keyword" "text" $ Just "keyword..." ] (ListModifier "post") + Nothing (Just "docs...") empty) `shouldBe` "[post] search-posts (\n\ @@ -102,3 +198,48 @@ spec = do \ text keyword,\n\ \ # keyword...\n\ \)," + toCode (Method "search-posts" + [ Parameter "blog-id" "uuid" $ Just "blog id..." + , Parameter "keyword" "text" $ Just "keyword..." + ] + (ListModifier "post") + (Just "search-posts-error") + Nothing + empty) `shouldBe` + "[post] search-posts (\n\ + \ uuid blog-id,\n\ + \ # blog id...\n\ + \ text keyword,\n\ + \ # keyword...\n\ + \) throws search-posts-error," + toCode (Method "search-posts" + [ Parameter "blog-id" "uuid" $ Just "blog id..." + , Parameter "keyword" "text" $ Just "keyword..." + ] + (ListModifier "post") + (Just "search-posts-error") + (Just "docs...") + empty) `shouldBe` + "[post] search-posts (\n\ + \ # docs...\n\ + \ uuid blog-id,\n\ + \ # blog id...\n\ + \ text keyword,\n\ + \ # keyword...\n\ + \) throws search-posts-error," + toCode (Method "search-posts" + [ Parameter "blog-id" "uuid" $ Just "blog id..." + , Parameter "keyword" "text" $ Just "keyword..." + ] + (ListModifier "post") + (Just "search-posts-error") + (Just "docs...") + methodAnno) `shouldBe` + "[http-get: \"/ping/\"]\n\ + \[post] search-posts (\n\ + \ # docs...\n\ + \ uuid blog-id,\n\ + \ # blog id...\n\ + \ text keyword,\n\ + \ # keyword...\n\ + \) throws search-posts-error," diff --git a/test/Nirum/Constructs/TypeDeclarationSpec.hs b/test/Nirum/Constructs/TypeDeclarationSpec.hs index 8726864..1819fec 100644 --- a/test/Nirum/Constructs/TypeDeclarationSpec.hs +++ b/test/Nirum/Constructs/TypeDeclarationSpec.hs @@ -165,7 +165,7 @@ spec = do ServiceDeclaration "null-service" nullService (Just "Null service declaration.") empty - pingService = Service [ Method "ping" [] "bool" Nothing empty ] + pingService = Service [ Method "ping" [] "bool" Nothing Nothing empty ] pingDecl = ServiceDeclaration "ping-service" pingService Nothing empty pingDecl' = diff --git a/test/Nirum/ParserSpec.hs b/test/Nirum/ParserSpec.hs index 2b6fd45..8ba4332 100644 --- a/test/Nirum/ParserSpec.hs +++ b/test/Nirum/ParserSpec.hs @@ -573,27 +573,54 @@ spec = do head $ rights [fromList [Annotation "http-get" "/get-name/"]] it "emits Method if succeeded to parse" $ do parse' "text get-name()" `shouldBeRight` - Method "get-name" [] "text" Nothing empty + Method "get-name" [] "text" Nothing Nothing empty parse' "text get-name (person user)" `shouldBeRight` Method "get-name" [Parameter "user" "person" Nothing] - "text" Nothing empty + "text" Nothing Nothing empty parse' "text get-name ( person user,text default )" `shouldBeRight` Method "get-name" [ Parameter "user" "person" Nothing , Parameter "default" "text" Nothing ] - "text" Nothing empty + "text" Nothing Nothing empty parse' "[http-get: \"/get-name/\"] text get-name ( person user,text default )" `shouldBeRight` Method "get-name" [ Parameter "user" "person" Nothing , Parameter "default" "text" Nothing ] - "text" Nothing httpGetAnnotation + "text" Nothing Nothing httpGetAnnotation + parse' "text get-name() throws name-error" `shouldBeRight` + Method "get-name" [] "text" (Just "name-error") Nothing empty + parse' "text get-name ( person user,text default )\n\ + \ throws get-name-error" `shouldBeRight` + Method "get-name" + [ Parameter "user" "person" Nothing + , Parameter "default" "text" Nothing + ] + "text" (Just "get-name-error") Nothing empty + parse' "[http-get:\"/get-name/\"]\n\ + \text get-name ( person user,text default )\n\ + \ throws get-name-error" `shouldBeRight` + Method "get-name" + [ Parameter "user" "person" Nothing + , Parameter "default" "text" Nothing + ] + "text" (Just "get-name-error") + Nothing + httpGetAnnotation it "can have docs" $ do parse' "text get-name (\n\ \ # Gets the name.\n\ \)" `shouldBeRight` - Method "get-name" [] "text" (Just "Gets the name.") empty + Method "get-name" [] "text" + Nothing (Just "Gets the name.") empty + parse' "text get-name (\n\ + \ # Gets the name.\n\ + \)throws name-error " `shouldBeRight` + Method "get-name" [] "text" + (Just "name-error") + (Just "Gets the name.") + empty parse' "text get-name (\n\ \ # Gets the name of the user.\n\ \ person user,\n\ @@ -601,6 +628,17 @@ spec = do Method "get-name" [Parameter "user" "person" Nothing] "text" + Nothing + (Just "Gets the name of the user.") + empty + parse' "text get-name (\n\ + \ # Gets the name of the user.\n\ + \ person user,\n\ + \) throws get-name-error" `shouldBeRight` + Method "get-name" + [Parameter "user" "person" Nothing] + "text" + (Just "get-name-error") (Just "Gets the name of the user.") empty parse' "text get-name (\n\ @@ -618,6 +656,7 @@ spec = do \the user has no name." ] "text" + Nothing (Just "Gets the name of the user.") empty it "fails to parse if there are parameters of the same facial name" $ do @@ -650,6 +689,7 @@ spec = do [Parameter "user-id" "uuid" Nothing] "user" Nothing + Nothing empty ]) Nothing @@ -659,13 +699,14 @@ spec = do \ user get-user (\n\ \ # Gets an user by its id.\n\ \ uuid user-id\n\ - \ ),\n\ + \ ) throws get-user-error,\n\ \);" `shouldBeRight` ServiceDeclaration "one-method-service" (Service [ Method "get-user" [Parameter "user-id" "uuid" Nothing] "user" + (Just "get-user-error") (Just "Gets an user by its id.") empty ]) @@ -687,11 +728,13 @@ spec = do (Service [ Method "create-user" [Parameter "user" "user" Nothing] "user" + Nothing (Just "Creates a new user") empty , Method "get-user" [Parameter "user-id" "uuid" Nothing] "user" + Nothing (Just "Gets an user by its id.") empty ]) diff --git a/test/Nirum/Targets/PythonSpec.hs b/test/Nirum/Targets/PythonSpec.hs index dc5b108..06e3210 100644 --- a/test/Nirum/Targets/PythonSpec.hs +++ b/test/Nirum/Targets/PythonSpec.hs @@ -772,6 +772,7 @@ spec = parallel $ do [Parameter "nonce" "text" Nothing] "bool" Nothing + Nothing empty] ping' = ServiceDeclaration "ping-service" pingService Nothing empty From 93727d2c36c607efd793da4e5d16b2443bb6ce9f Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Sat, 13 Aug 2016 03:17:22 +0900 Subject: [PATCH 2/2] Add 'service' and 'throws' in reserved keywords --- src/Nirum/Constructs/Identifier.hs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Nirum/Constructs/Identifier.hs b/src/Nirum/Constructs/Identifier.hs index 5c3e8e6..2f45a5b 100644 --- a/src/Nirum/Constructs/Identifier.hs +++ b/src/Nirum/Constructs/Identifier.hs @@ -52,7 +52,14 @@ import Nirum.Constructs (Construct(toCode)) data Identifier = Identifier T.Text deriving (Show) reservedKeywords :: S.Set Identifier -reservedKeywords = ["boxed", "enum", "record", "type", "union"] +reservedKeywords = [ "boxed" + , "enum" + , "record" + , "service" + , "throws" + , "type" + , "union" + ] identifierRule :: Parser Identifier identifierRule = do