Skip to content

Commit

Permalink
Parse trailling comma & multiline
Browse files Browse the repository at this point in the history
  • Loading branch information
kanghyojun committed Apr 25, 2018
1 parent d1e9b82 commit 25da998
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 40 deletions.
31 changes: 18 additions & 13 deletions src/Nirum/Parser.hs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import qualified System.IO as SIO

import qualified Data.List as L
import Data.Map.Strict as Map hiding (foldl, toList)
import Data.Maybe
import Data.Set hiding (foldl)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
Expand Down Expand Up @@ -635,14 +634,16 @@ importName forwardNames = do
aSet <- annotationSet <?> "import annotations"
spaces
iName <- identifier <?> "name to import"
aName <- optional $ try $ do
spaces
string' "as"
spaces
n <- uniqueIdentifier forwardNames "alias name to import"
spaces
return n
return (iName, fromMaybe iName aName, aSet)
hasAlias <- optional $ try $ do
spaces
string' "as"
aName <- case hasAlias of
Just _ -> do
spaces
uniqueIdentifier forwardNames "alias name to import"
Nothing ->
return iName
return (aName, iName, aSet)

imports :: [Identifier] -> Parser [TypeDeclaration]
imports forwardNames = do
Expand All @@ -653,18 +654,22 @@ imports forwardNames = do
char '('
spaces
idents <- many' [] $ \ importNames' -> do
let forwardNames' = [ i | (_, i, _) <- importNames' ] ++
notFollowedBy $ choice [char ')', char ',' >> spaces >> char ')']
let forwardNames' = [ i | (i, _, _) <- importNames' ] ++
forwardNames
unless (L.null importNames') $ do
string' ","
spaces
i <- importName forwardNames'
n <- importName forwardNames'
spaces
return i
return n
when (L.null idents) $ fail "parentheses cannot be empty"
void $ optional $ string' ","
spaces
char ')'
spaces
char ';'
return [ Import path source imp aSet
return [ Import path imp source aSet
| (imp, source, aSet) <- idents
]

Expand Down
64 changes: 37 additions & 27 deletions test/Nirum/ParserSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,36 +1216,46 @@ service method-dups (
[ Import ["foo", "bar"] "foo" "c" empty
, Import ["foo", "bar"] "bar" "d" empty
]

it "errors if parentheses have nothing" $
expectError "import foo.bar ();" 1 17
it "disallows when there are duplicated alias names" $
expectError "import foo.bar (lorem as yolo, ipsum as yolo);" 1 41

describe "module'" $ context "handling name duplications" $ do
let (_, expectError) = helperFuncs P.module'
let examples =
-- Vertical alignment of `dup` is an intention; it purposes
-- to generate the same error offsets.
[ "type dup = text;"
, "unboxed dup (text);"
, "record dup (text a);"
, "enum dup = m1 | m2;"
, "enum e1 = dup | foo;"
, "union dup = t1 | t2;"
, "union u1 = dup | foo;"
, "service dup (text ping ());"
]
let importExample = "import foo (dup);"
let shiftDigit = \ case
'1' -> '3'
'2' -> '4'
c -> c
let inputs = [ (a, if a == b then T.map shiftDigit b else b)
| a <- importExample : examples
, b <- examples
]
forM_ inputs $ \ (forward, shadowing) ->
let input = T.concat [forward, "\n", shadowing]
in
specify (T.unpack input) $ expectError input 2 12
describe "module'" $ do
context "handling name duplications" $ do
let (_, expectError) = helperFuncs P.module'
let examples =
-- Vertical alignment of `dup` is an intention; it purposes
-- to generate the same error offsets.
[ "type dup = text;"
, "unboxed dup (text);"
, "record dup (text a);"
, "enum dup = m1 | m2;"
, "enum e1 = dup | foo;"
, "union dup = t1 | t2;"
, "union u1 = dup | foo;"
, "service dup (text ping ());"
]
let importExample = "import foo (dup);"
let shiftDigit = \ case
'1' -> '3'
'2' -> '4'
c -> c
let inputs = [ (a, if a == b then T.map shiftDigit b else b)
| a <- importExample : examples
, b <- examples
]
forM_ inputs $ \ (forward, shadowing) ->
let input = T.concat [forward, "\n", shadowing]
in
specify (T.unpack input) $ expectError input 2 12
specify "allows import duplicated source name when it use alias" $ do
let (parse', _) = helperFuncs P.module'
parse' "import foo.bar (a);\n import lorem.ipsum (a as dolor);" `shouldBeRight`
Module [ Import ["foo", "bar"] "a" "a" empty
, Import ["lorem", "ipsum"] "dolor" "a" empty
] Nothing

specify "parse & parseFile" $ do
files <- getDirectoryContents "examples"
Expand Down

0 comments on commit 25da998

Please sign in to comment.