Rain: changed the innerBlock parser to work with the new rules for declarations in par blocks, and also simplified its output slightly

This commit is contained in:
Neil Brown 2007-09-14 12:22:12 +00:00
parent 59d86a0afc
commit ff9b0d6611
2 changed files with 42 additions and 18 deletions

View File

@ -246,24 +246,40 @@ expression
<|> do {(m,op) <- monadicArithOp ; rhs <- subExpr' ; return $ A.Monadic m op rhs} <|> do {(m,op) <- monadicArithOp ; rhs <- subExpr' ; return $ A.Monadic m op rhs}
<|> do {sLeftR ; e <- expression ; sRightR ; return e} <|> do {sLeftR ; e <- expression ; sRightR ; return e}
innerBlock :: RainParser A.Structured data InnerBlockLineState = Decls | NoMoreDecls | Mixed deriving (Eq)
innerBlock = do {m <- sLeftC ; lines <- linesToEnd ; return $ A.Several m lines}
innerBlock :: Bool -> RainParser A.Structured
innerBlock declsMustBeFirst = do m <- sLeftC
lines <- linesToEnd (if declsMustBeFirst then Decls else Mixed)
case lines of
Left single -> return single
Right lines -> return $ A.Several m lines
where where
wrapProc :: A.Process -> A.Structured wrapProc :: A.Process -> A.Structured
wrapProc x = A.OnlyP (findMeta x) x wrapProc x = A.OnlyP (findMeta x) x
linesToEnd :: RainParser [A.Structured]
linesToEnd = do {(m,decl) <- declaration ; rest <- linesToEnd ; return [decl $ A.Several m rest]} makeList :: Either A.Structured [A.Structured] -> [A.Structured]
<|> do {st <- statement ; rest <- linesToEnd ; return $ (wrapProc st) : rest} makeList (Left s) = [s]
makeList (Right ss) = ss
--Returns either a single line (which means the immediate next line is a declaration) or a list of remaining lines
linesToEnd :: InnerBlockLineState -> RainParser (Either A.Structured [A.Structured])
linesToEnd state
= (if state /= NoMoreDecls then do {(m,decl) <- declaration ; rest <- linesToEnd state ; return $ Left $ decl $ A.Several m (makeList rest)} else pzero)
<|> do {st <- statement ; rest <- linesToEnd nextState ; return $ Right $ (wrapProc st) : (makeList rest)}
--Although return is technically a statement, we parse it here because it can only occur inside a block, --Although return is technically a statement, we parse it here because it can only occur inside a block,
--and we don't want to wrap it in an A.OnlyP: --and we don't want to wrap it in an A.OnlyP:
<|> do {m <- sReturn ; exp <- expression ; sSemiColon ; rest <- linesToEnd ; <|> do {m <- sReturn ; exp <- expression ; sSemiColon ; rest <- linesToEnd nextState ;
return $ (A.OnlyEL m $ A.ExpressionList (findMeta exp) [exp]) : rest} return $ Right $ (A.OnlyEL m $ A.ExpressionList (findMeta exp) [exp]) : (makeList rest)}
<|> do {sRightC ; return []} <|> do {sRightC ; return $ Right []}
<?> "statement, declaration, or end of block" <?> "statement, declaration, or end of block"
where
nextState = if state == Mixed then Mixed else NoMoreDecls
block :: RainParser A.Process block :: RainParser A.Process
block = do { optionalSeq ; b <- innerBlock ; return $ A.Seq (findMeta b) b} block = do { optionalSeq ; b <- innerBlock False ; return $ A.Seq (findMeta b) b}
<|> do { m <- sPar ; b <- innerBlock ; return $ A.Par m A.PlainPar b} <|> do { m <- sPar ; b <- innerBlock True ; return $ A.Par m A.PlainPar b}
optionalSeq :: RainParser () optionalSeq :: RainParser ()
optionalSeq = option () (sSeq >> return ()) optionalSeq = option () (sSeq >> return ())

View File

@ -338,29 +338,37 @@ testPar =
,pass ("par { {} {} }",RP.statement, ,pass ("par { {} {} }",RP.statement,
assertEqual "Par Skip Test" $ A.Par m A.PlainPar $ A.Several m [A.OnlyP m emptyBlock, A.OnlyP m emptyBlock] ) assertEqual "Par Skip Test" $ A.Par m A.PlainPar $ A.Several m [A.OnlyP m emptyBlock, A.OnlyP m emptyBlock] )
--Rain only allows declarations at the beginning of a par block:
,pass ("par {int:x; {} }",RP.statement,
assertEqual "Par Decl Test 0" $ A.Par m A.PlainPar $ A.Spec m (A.Specification m (simpleName "x") $ A.Declaration m A.Int) $ A.Several m
[A.OnlyP m $ A.Seq m $ A.Several m []] )
,fail ("par { {} int: x; }",RP.statement)
] ]
-- | Test innerBlock, particularly with declarations mixed with statements: -- | Test innerBlock, particularly with declarations mixed with statements:
testBlock :: [ParseTest A.Structured] testBlock :: [ParseTest A.Structured]
testBlock = testBlock =
[ [
pass("{ a = b; }",RP.innerBlock,assertPatternMatch "testBlock 0" (tag2 A.Several DontCare [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"]) ) pass("{ a = b; }",RP.innerBlock False,assertPatternMatch "testBlock 0" (tag2 A.Several DontCare [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"]) )
,pass("{ a = b; b = c; }",RP.innerBlock,assertPatternMatch "testBlock 1" (tag2 A.Several DontCare ,pass("{ a = b; b = c; }",RP.innerBlock False,assertPatternMatch "testBlock 1" (tag2 A.Several DontCare
[tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b",tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c"]) ) [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b",tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c"]) )
,pass("{ uint8: x; a = b; }",RP.innerBlock,assertPatternMatch "testBlock 2" $ tag2 A.Several DontCare [tag3 A.Spec DontCare ,pass("{ uint8: x; a = b; }",RP.innerBlock False,assertPatternMatch "testBlock 2" $ tag3 A.Spec DontCare
(tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare (tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare
[tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"] [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"]
]) )
,pass("{ uint8: x; a = b; b = c; }",RP.innerBlock,assertPatternMatch "testBlock 3" $ tag2 A.Several DontCare [tag3 A.Spec DontCare ,pass("{ uint8: x; a = b; b = c; }",RP.innerBlock False,assertPatternMatch "testBlock 3" $ tag3 A.Spec DontCare
(tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare (tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare
[tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b",tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c"] [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b",tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c"]
]) )
,pass("{ b = c; uint8: x; a = b; }",RP.innerBlock,assertPatternMatch "testBlock 4" $ tag2 A.Several DontCare [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c", ,pass("{ b = c; uint8: x; a = b; }",RP.innerBlock False,assertPatternMatch "testBlock 4" $ tag2 A.Several DontCare [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "b" "c",
tag3 A.Spec DontCare tag3 A.Spec DontCare
(tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare (tag3 A.Specification DontCare (simpleNamePattern "x") $ tag2 A.Declaration DontCare A.Byte) $ tag2 A.Several DontCare
[tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"] [tag2 A.OnlyP DontCare $ makeSimpleAssignPattern "a" "b"]
]) ])
,fail("{b}",RP.innerBlock) ,fail("{b}",RP.innerBlock False)
] ]
testEach :: [ParseTest A.Process] testEach :: [ParseTest A.Process]