diff --git a/src/Language/Fortran/AST.hs b/src/Language/Fortran/AST.hs index 353de09e..d2ad4365 100644 --- a/src/Language/Fortran/AST.hs +++ b/src/Language/Fortran/AST.hs @@ -610,7 +610,12 @@ data Expression a = -- ^ @%@ notation for variables inside data types | ExpFunctionCall a SrcSpan (Expression a) (Maybe (AList Argument a)) -- ^ A function expression applied to a list of arguments. - | ExpImpliedDo a SrcSpan (AList Expression a) (DoSpecification a) + | ExpImpliedDo a SrcSpan + (AList Expression a) + (Expression a) -- ^ Name @(ExpValue (ValVariable n))@ + (Expression a) -- ^ Initial value + (Expression a) -- ^ End value + (Maybe (Expression a)) -- ^ Step (or 1 if 'Nothing') -- ^ Implied do (i.e. one-liner do loops) | ExpInitialisation a SrcSpan (AList Expression a) -- ^ Array initialisation diff --git a/src/Language/Fortran/Parser/Fixed/Fortran66.y b/src/Language/Fortran/Parser/Fixed/Fortran66.y index 75c55e41..e9c01ffd 100644 --- a/src/Language/Fortran/Parser/Fixed/Fortran66.y +++ b/src/Language/Fortran/Parser/Fixed/Fortran66.y @@ -242,7 +242,8 @@ IO_ELEMENT :: { Expression A0 } -- differentiate it at this stage from VARIABLE. Hence, it is omitted to prevent -- reduce/reduce conflict. | SUBSCRIPT { $1 } -| '(' IO_ELEMENTS ',' DO_SPECIFICATION ')' { ExpImpliedDo () (getTransSpan $1 $5) $2 $4 } +| '(' IO_ELEMENTS ',' ELEMENT '=' EXPRESSION ',' INT_OR_VAR ')' + { ExpImpliedDo () (getTransSpan $1 $9) $2 $4 $6 $8 Nothing } ELEMENT :: { Expression A0 } : VARIABLE { $1 } diff --git a/src/Language/Fortran/Parser/Fixed/Fortran77.y b/src/Language/Fortran/Parser/Fixed/Fortran77.y index 119dde7e..e6c030fb 100644 --- a/src/Language/Fortran/Parser/Fixed/Fortran77.y +++ b/src/Language/Fortran/Parser/Fixed/Fortran77.y @@ -430,7 +430,10 @@ IN_IOLIST :: { AList Expression A0 } IN_IO_ELEMENT :: { Expression A0 } : SUBSCRIPT { $1 } -| '(' IN_IOLIST ',' DO_SPECIFICATION ')' { ExpImpliedDo () (getTransSpan $1 $5) (aReverse $2) $4 } +| '(' IN_IOLIST ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ')' + { ExpImpliedDo () (getTransSpan $1 $9) (aReverse $2) $4 $6 $8 Nothing } +| '(' IN_IOLIST ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { ExpImpliedDo () (getTransSpan $1 $11) (aReverse $2) $4 $6 $8 (Just $10) } OUT_IOLIST :: { AList Expression A0 } : OUT_IOLIST ',' EXPRESSION { setSpan (getTransSpan $1 $3) $ $3 `aCons` $1} @@ -782,19 +785,29 @@ EXPRESSION :: { Expression A0 } | '&' INTEGER_LITERAL { ExpReturnSpec () (getTransSpan $1 $2) $2 } IMPLIED_DO :: { Expression A0 } -: '(' EXPRESSION ',' DO_SPECIFICATION ')' { - let expList = AList () (getSpan $2) [ $2 ] - in ExpImpliedDo () (getTransSpan $1 $5) expList $4 - } -| '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')' { - let expList = AList () (getTransSpan $2 $4) [ $2, $4 ] - in ExpImpliedDo () (getTransSpan $1 $5) expList $6 - } -| '(' EXPRESSION ',' EXPRESSION ',' EXPRESSION_LIST ',' DO_SPECIFICATION ')' { - let { exps = reverse $6; +: '(' EXPRESSION ',' EXPRESSION ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $11) es $6 $8 $10 Nothing } +| '(' EXPRESSION ',' EXPRESSION ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $13) es $6 $8 $10 (Just $12) } +{- +: '(' EXPRESSION_LIST ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 Nothing } +| '(' EXPRESSION_LIST ',' ELEMENT '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 (Just $10) } +-} +{- TODO +| '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')' + { let expList = AList () (getTransSpan $2 $4) [ $2, $4 ] + in ExpImpliedDo () (getTransSpan $1 $5) expList $6 } +| '(' EXPRESSION ',' EXPRESSION ',' EXPRESSION_LIST ',' DO_SPECIFICATION ')' + { let { exps = reverse $6; expList = AList () (getTransSpan $2 exps) ($2 : $4 : reverse $6) } - in ExpImpliedDo () (getTransSpan $1 $9) expList $8 - } + in ExpImpliedDo () (getTransSpan $1 $9) expList $8 } +-} EXPRESSION_LIST :: { [ Expression A0 ] } : EXPRESSION_LIST ',' EXPRESSION { $3 : $1 } diff --git a/src/Language/Fortran/Parser/Free/Fortran2003.y b/src/Language/Fortran/Parser/Free/Fortran2003.y index f13dc07d..a16d3265 100644 --- a/src/Language/Fortran/Parser/Free/Fortran2003.y +++ b/src/Language/Fortran/Parser/Free/Fortran2003.y @@ -930,8 +930,10 @@ IN_IOLIST :: { [ Expression A0 ] } IN_IO_ELEMENT :: { Expression A0 } : DATA_REF { $1 } +{- TODO | '(' IN_IOLIST ',' DO_SPECIFICATION ')' { ExpImpliedDo () (getTransSpan $1 $5) (fromReverseList $2) $4 } +-} OUT_IOLIST :: { [ Expression A0 ] } : OUT_IOLIST ',' EXPRESSION { $3 : $1} @@ -1299,9 +1301,21 @@ DO_SPECIFICATION :: { DoSpecification A0 } { DoSpecification () (getTransSpan $1 $3) $1 $3 Nothing } IMPLIED_DO :: { Expression A0 } -: '(' EXPRESSION ',' DO_SPECIFICATION ')' - { let expList = AList () (getSpan $2) [ $2 ] - in ExpImpliedDo () (getTransSpan $1 $5) expList $4 } +: '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $11) es $6 $8 $10 Nothing } +| '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $13) es $6 $8 $10 (Just $12) } +{- +: '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 Nothing } +| '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 (Just $10) } +-} +{- TODO | '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')' { let expList = AList () (getTransSpan $2 $4) [ $2, $4 ] in ExpImpliedDo () (getTransSpan $1 $5) expList $6 } @@ -1309,6 +1323,7 @@ IMPLIED_DO :: { Expression A0 } { let { exps = reverse $6; expList = AList () (getTransSpan $2 exps) ($2 : $4 : reverse $6) } in ExpImpliedDo () (getTransSpan $1 $9) expList $8 } +-} FORALL :: { Statement A0 } : id ':' forall FORALL_HEADER { diff --git a/src/Language/Fortran/Parser/Free/Fortran90.y b/src/Language/Fortran/Parser/Free/Fortran90.y index ff748ee7..ed462e5f 100644 --- a/src/Language/Fortran/Parser/Free/Fortran90.y +++ b/src/Language/Fortran/Parser/Free/Fortran90.y @@ -741,8 +741,10 @@ IN_IOLIST :: { [ Expression A0 ] } IN_IO_ELEMENT :: { Expression A0 } : DATA_REF { $1 } +{- TODO | '(' IN_IOLIST ',' DO_SPECIFICATION ')' { ExpImpliedDo () (getTransSpan $1 $5) (fromReverseList $2) $4 } +-} OUT_IOLIST :: { [ Expression A0 ] } : OUT_IOLIST ',' EXPRESSION { $3 : $1} @@ -1091,9 +1093,21 @@ DO_SPECIFICATION :: { DoSpecification A0 } { DoSpecification () (getTransSpan $1 $3) $1 $3 Nothing } IMPLIED_DO :: { Expression A0 } -: '(' EXPRESSION ',' DO_SPECIFICATION ')' - { let expList = AList () (getSpan $2) [ $2 ] - in ExpImpliedDo () (getTransSpan $1 $5) expList $4 } +: '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $11) es $6 $8 $10 Nothing } +| '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $13) es $6 $8 $10 (Just $12) } +{- +: '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 Nothing } +| '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 (Just $10) } +-} +{- TODO | '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')' { let expList = AList () (getTransSpan $2 $4) [ $2, $4 ] in ExpImpliedDo () (getTransSpan $1 $5) expList $6 } @@ -1101,6 +1115,7 @@ IMPLIED_DO :: { Expression A0 } { let { exps = reverse $6; expList = AList () (getTransSpan $2 exps) ($2 : $4 : reverse $6) } in ExpImpliedDo () (getTransSpan $1 $9) expList $8 } +-} EXPRESSION_LIST :: { [ Expression A0 ] } : EXPRESSION_LIST ',' EXPRESSION { $3 : $1 } diff --git a/src/Language/Fortran/Parser/Free/Fortran95.y b/src/Language/Fortran/Parser/Free/Fortran95.y index ca2ae1a0..ffadbfad 100644 --- a/src/Language/Fortran/Parser/Free/Fortran95.y +++ b/src/Language/Fortran/Parser/Free/Fortran95.y @@ -750,8 +750,10 @@ IN_IOLIST :: { [ Expression A0 ] } IN_IO_ELEMENT :: { Expression A0 } : DATA_REF { $1 } +{- TODO | '(' IN_IOLIST ',' DO_SPECIFICATION ')' { ExpImpliedDo () (getTransSpan $1 $5) (fromReverseList $2) $4 } +-} OUT_IOLIST :: { [ Expression A0 ] } : OUT_IOLIST ',' EXPRESSION { $3 : $1} @@ -1102,9 +1104,21 @@ DO_SPECIFICATION :: { DoSpecification A0 } { DoSpecification () (getTransSpan $1 $3) $1 $3 Nothing } IMPLIED_DO :: { Expression A0 } -: '(' EXPRESSION ',' DO_SPECIFICATION ')' - { let expList = AList () (getSpan $2) [ $2 ] - in ExpImpliedDo () (getTransSpan $1 $5) expList $4 } +: '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $11) es $6 $8 $10 Nothing } +| '(' EXPRESSION ',' EXPRESSION ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getTransSpan $2 $4) [$2, $4] + in ExpImpliedDo () (getTransSpan $1 $13) es $6 $8 $10 (Just $12) } +{- +: '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 Nothing } +| '(' EXPRESSION_LIST ',' DATA_REF '=' EXPRESSION ',' EXPRESSION ',' EXPRESSION ')' + { let es = AList () (getSpan $2) (reverse $2) + in ExpImpliedDo () (getTransSpan $1 $9) es $4 $6 $8 (Just $10) } +-} +{- TODO | '(' EXPRESSION ',' EXPRESSION ',' DO_SPECIFICATION ')' { let expList = AList () (getTransSpan $2 $4) [ $2, $4 ] in ExpImpliedDo () (getTransSpan $1 $5) expList $6 } @@ -1112,6 +1126,7 @@ IMPLIED_DO :: { Expression A0 } { let { exps = reverse $6; expList = AList () (getTransSpan $2 exps) ($2 : $4 : reverse $6) } in ExpImpliedDo () (getTransSpan $1 $9) expList $8 } +-} FORALL :: { Statement A0 } : id ':' forall FORALL_HEADER { diff --git a/src/Language/Fortran/PrettyPrint.hs b/src/Language/Fortran/PrettyPrint.hs index ebe9530c..b4d214b9 100644 --- a/src/Language/Fortran/PrettyPrint.hs +++ b/src/Language/Fortran/PrettyPrint.hs @@ -947,8 +947,11 @@ instance Pretty (Expression a) where pprint' v (ExpFunctionCall _ _ e mes) = pprint' v e <> parens (pprint' v mes) - pprint' v (ExpImpliedDo _ _ es dospec) = - pprint' v es <> comma <+> pprint' v dospec + pprint' v (ExpImpliedDo _ _ es n initial limit mStride) = + pprint' v es + <> comma <> pprint' v n <> " = " <> pprint' v initial + <> comma <> pprint' v limit + <> comma pprint' v mStride pprint' v (ExpInitialisation _ _ es) = "(/" <> pprint' v es <> "/)" diff --git a/test/Language/Fortran/Parser/Fixed/Fortran77/ParserSpec.hs b/test/Language/Fortran/Parser/Fixed/Fortran77/ParserSpec.hs index a698402d..734016a7 100644 --- a/test/Language/Fortran/Parser/Fixed/Fortran77/ParserSpec.hs +++ b/test/Language/Fortran/Parser/Fixed/Fortran77/ParserSpec.hs @@ -53,19 +53,15 @@ spec = sParser " endfile i" `shouldBe'` StEndfile2 () u (varGen "i") it "parses 'read *, (x, y(i), i = 1, 10, 2)'" $ do - let stAssign = StExpressionAssign () u (varGen "i") (intGen 1) - doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2) - impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])] - impliedDo = ExpImpliedDo () u impliedDoVars doSpec + let impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])] + impliedDo = ExpImpliedDo () u impliedDoVars (varGen "i") (intGen 1) (intGen 10) (Just (intGen 2)) iolist = AList () u [ impliedDo ] expectedSt = StRead2 () u starVal (Just iolist) sParser " read *, (x, y(i), i = 1, 10, 2)" `shouldBe'` expectedSt it "parses '(x, y(i), i = 1, 10, 2)'" $ do - let stAssign = StExpressionAssign () u (varGen "i") (intGen 1) - doSpec = DoSpecification () u stAssign (intGen 10) (Just $ intGen 2) - impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])] - impliedDo = ExpImpliedDo () u impliedDoVars doSpec + let impliedDoVars = AList () u [ varGen "x", ExpSubscript () u (varGen "y") (AList () u [ IxSingle () u Nothing $ varGen "i" ])] + impliedDo = ExpImpliedDo () u impliedDoVars (varGen "i") (intGen 1) (intGen 10) (Just (intGen 2)) eParser "(x, y(i), i = 1, 10, 2)" `shouldBe'` impliedDo it "parses main program unit" $ do diff --git a/test/Language/Fortran/Parser/Free/Common.hs b/test/Language/Fortran/Parser/Free/Common.hs index 5d75283a..7ba66dcc 100644 --- a/test/Language/Fortran/Parser/Free/Common.hs +++ b/test/Language/Fortran/Parser/Free/Common.hs @@ -196,3 +196,14 @@ specFreeCommon bParser sParser eParser = (intGen 2) (intGen 3) sParser "if (x) 1, 2, 3" `shouldBe'` stIf + + describe "Assorted" $ do + it "parses write with implied do" $ do + let cp1 = ControlPair () u Nothing (intGen 10) + cp2 = ControlPair () u (Just "format") (varGen "x") + ciList = fromList () [ cp1, cp2 ] + alist = fromList () [ varGen "i", varGen "j" ] + impdo = ExpImpliedDo () u alist (varGen "i") (intGen 1) (intGen 42) (Just (intGen 2)) + outList = fromList () [impdo] + st = StWrite () u ciList (Just outList) + sParser "write (10, FORMAT = x) (i, j, i = 1, 42, 2)" `shouldBe'` st diff --git a/test/Language/Fortran/Parser/Free/Fortran90Spec.hs b/test/Language/Fortran/Parser/Free/Fortran90Spec.hs index 5cdbbde6..26060eff 100644 --- a/test/Language/Fortran/Parser/Free/Fortran90Spec.hs +++ b/test/Language/Fortran/Parser/Free/Fortran90Spec.hs @@ -485,17 +485,6 @@ spec = let st = StPrint () u starVal (Just $ fromList () [ varGen "hex" ]) sParser "print *, hex" `shouldBe'` st - it "parses write with implied do" $ do - let cp1 = ControlPair () u Nothing (intGen 10) - cp2 = ControlPair () u (Just "format") (varGen "x") - ciList = fromList () [ cp1, cp2 ] - assign = StExpressionAssign () u (varGen "i") (intGen 1) - doSpec = DoSpecification () u assign (intGen 42) (Just $ intGen 2) - alist = fromList () [ varGen "i", varGen "j" ] - outList = fromList () [ ExpImpliedDo () u alist doSpec ] - st = StWrite () u ciList (Just outList) - sParser "write (10, FORMAT = x) (i, j, i = 1, 42, 2)" `shouldBe'` st - it "parses use statement with renames" $ do let renames = fromList () [ UseRename () u (varGen "sprod") (varGen "prod") diff --git a/test/Language/Fortran/Parser/Free/Fortran95Spec.hs b/test/Language/Fortran/Parser/Free/Fortran95Spec.hs index 4dbbe5f0..35f79012 100644 --- a/test/Language/Fortran/Parser/Free/Fortran95Spec.hs +++ b/test/Language/Fortran/Parser/Free/Fortran95Spec.hs @@ -537,17 +537,6 @@ spec = let st = StPrint () u starVal (Just $ fromList () [ varGen "hex" ]) sParser "print *, hex" `shouldBe'` st - it "parses write with implied do" $ do - let cp1 = ControlPair () u Nothing (intGen 10) - cp2 = ControlPair () u (Just "format") (varGen "x") - ciList = fromList () [ cp1, cp2 ] - assign = StExpressionAssign () u (varGen "i") (intGen 1) - doSpec = DoSpecification () u assign (intGen 42) (Just $ intGen 2) - alist = fromList () [ varGen "i", varGen "j" ] - outList = fromList () [ ExpImpliedDo () u alist doSpec ] - st = StWrite () u ciList (Just outList) - sParser "write (10, FORMAT = x) (i, j, i = 1, 42, 2)" `shouldBe'` st - it "parses use statement" $ do let renames = fromList () [ UseRename () u (varGen "sprod") (varGen "prod")