Move constant checking from the occam parser into a pass.
The parser now doesn't do any constant folding or checking.
This commit is contained in:
parent
7f6cb6e0c3
commit
79eefd5e98
|
@ -17,15 +17,19 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
-- | The occam-specific frontend passes.
|
-- | The occam-specific frontend passes.
|
||||||
module OccamPasses (occamPasses, foldConstants) where
|
module OccamPasses (occamPasses, foldConstants, checkConstants) where
|
||||||
|
|
||||||
|
import Control.Monad
|
||||||
import Data.Generics
|
import Data.Generics
|
||||||
|
|
||||||
import qualified AST as A
|
import qualified AST as A
|
||||||
import CompState
|
import CompState
|
||||||
import EvalConstants
|
import EvalConstants
|
||||||
|
import EvalLiterals
|
||||||
|
import Metadata
|
||||||
import Pass
|
import Pass
|
||||||
import qualified Properties as Prop
|
import qualified Properties as Prop
|
||||||
|
import ShowCode
|
||||||
|
|
||||||
-- | Occam-specific frontend passes.
|
-- | Occam-specific frontend passes.
|
||||||
occamPasses :: [Pass]
|
occamPasses :: [Pass]
|
||||||
|
@ -33,6 +37,9 @@ occamPasses = makePassesDep' ((== FrontendOccam) . csFrontend)
|
||||||
[ ("Fold constants", foldConstants,
|
[ ("Fold constants", foldConstants,
|
||||||
[],
|
[],
|
||||||
[Prop.constantsFolded])
|
[Prop.constantsFolded])
|
||||||
|
, ("Check mandatory constants", checkConstants,
|
||||||
|
[Prop.constantsFolded],
|
||||||
|
[Prop.constantsChecked])
|
||||||
, ("Dummy occam pass", dummyOccamPass,
|
, ("Dummy occam pass", dummyOccamPass,
|
||||||
[],
|
[],
|
||||||
Prop.agg_namesDone ++ [Prop.expressionTypesChecked,
|
Prop.agg_namesDone ++ [Prop.expressionTypesChecked,
|
||||||
|
@ -66,6 +73,30 @@ foldConstants = doGeneric `extM` doSpecification `extM` doExpression
|
||||||
(e'', _, _) <- constantFold e'
|
(e'', _, _) <- constantFold e'
|
||||||
return e''
|
return e''
|
||||||
|
|
||||||
|
-- | Check that things that must be constant are.
|
||||||
|
checkConstants :: Data t => t -> PassM t
|
||||||
|
checkConstants = doGeneric `extM` doDimension `extM` doOption
|
||||||
|
where
|
||||||
|
doGeneric :: Data t => t -> PassM t
|
||||||
|
doGeneric = makeGeneric checkConstants
|
||||||
|
|
||||||
|
-- Check array dimensions are constant.
|
||||||
|
doDimension :: A.Dimension -> PassM A.Dimension
|
||||||
|
doDimension d@(A.Dimension e)
|
||||||
|
= do when (not $ isConstant e) $
|
||||||
|
diePC (findMeta e) $ formatCode "Array dimension must be constant: %" e
|
||||||
|
doGeneric d
|
||||||
|
doDimension d = doGeneric d
|
||||||
|
|
||||||
|
-- Check case options are constant.
|
||||||
|
doOption :: A.Option -> PassM A.Option
|
||||||
|
doOption o@(A.Option _ es _)
|
||||||
|
= do sequence_ [when (not $ isConstant e) $
|
||||||
|
diePC (findMeta e) $ formatCode "Case option must be constant: %" e
|
||||||
|
| e <- es]
|
||||||
|
doGeneric o
|
||||||
|
doOption o = doGeneric o
|
||||||
|
|
||||||
-- | A dummy pass for things that haven't been separated out into passes yet.
|
-- | A dummy pass for things that haven't been separated out into passes yet.
|
||||||
dummyOccamPass :: Data t => t -> PassM t
|
dummyOccamPass :: Data t => t -> PassM t
|
||||||
dummyOccamPass = return
|
dummyOccamPass = return
|
||||||
|
|
|
@ -108,7 +108,58 @@ testFoldConstants = TestList
|
||||||
four = intLiteral 4
|
four = intLiteral 4
|
||||||
six = intLiteral 6
|
six = intLiteral 6
|
||||||
|
|
||||||
|
-- | Test 'OccamPasses.checkConstants'.
|
||||||
|
testCheckConstants :: Test
|
||||||
|
testCheckConstants = TestList
|
||||||
|
[
|
||||||
|
-- Valid dimensions in array types
|
||||||
|
testOK 0 (A.Int)
|
||||||
|
, testOK 1 (A.Array [dim10] A.Int)
|
||||||
|
, testOK 2 (A.Array [dimU] A.Int)
|
||||||
|
, testOK 3 (A.Array [dim10, dim10] A.Int)
|
||||||
|
, testOK 4 (A.Array [dim10, dimU] A.Int)
|
||||||
|
|
||||||
|
-- Invalid dimensions in array types
|
||||||
|
, testFail 10 (A.Array [dimVar] A.Int)
|
||||||
|
, testFail 11 (A.Array [dimVar, dimVar] A.Int)
|
||||||
|
, testFail 12 (A.Array [dim10, dimVar] A.Int)
|
||||||
|
, testFail 13 (A.Array [dimU, dimVar] A.Int)
|
||||||
|
, testFail 14 (A.Array [dim10, dim10, dimU, dimU, dimVar] A.Int)
|
||||||
|
|
||||||
|
-- Valid Case options
|
||||||
|
, testOK 20 (A.Option m [lit10] skip)
|
||||||
|
, testOK 21 (A.Option m [lit10, lit10] skip)
|
||||||
|
, testOK 22 (A.Option m [lit10, lit10, lit10] skip)
|
||||||
|
|
||||||
|
-- Invalid Case options
|
||||||
|
, testFail 30 (A.Option m [var] skip)
|
||||||
|
, testFail 31 (A.Option m [lit10, var] skip)
|
||||||
|
, testFail 32 (A.Option m [var, lit10] skip)
|
||||||
|
, testFail 33 (A.Option m [lit10, lit10, lit10, var] skip)
|
||||||
|
]
|
||||||
|
where
|
||||||
|
testOK :: (Show a, Data a) => Int -> a -> Test
|
||||||
|
testOK n orig
|
||||||
|
= TestCase $ testPass ("testCheckConstants" ++ show n)
|
||||||
|
orig (OccamPasses.checkConstants orig)
|
||||||
|
(return ())
|
||||||
|
|
||||||
|
testFail :: (Show a, Data a) => Int -> a -> Test
|
||||||
|
testFail n orig
|
||||||
|
= TestCase $ testPassShouldFail ("testCheckConstants" ++ show n)
|
||||||
|
(OccamPasses.checkConstants orig)
|
||||||
|
(return ())
|
||||||
|
|
||||||
|
dim10 = A.Dimension $ intLiteral 10
|
||||||
|
dimU = A.UnknownDimension
|
||||||
|
dimVar = A.Dimension $ exprVariable "var"
|
||||||
|
|
||||||
|
lit10 = intLiteral 10
|
||||||
|
var = exprVariable "var"
|
||||||
|
skip = A.Skip m
|
||||||
|
|
||||||
tests :: Test
|
tests :: Test
|
||||||
tests = TestLabel "OccamPassesTest" $ TestList
|
tests = TestLabel "OccamPassesTest" $ TestList
|
||||||
[ testFoldConstants
|
[ testFoldConstants
|
||||||
|
, testCheckConstants
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,6 @@ import Text.ParserCombinators.Parsec
|
||||||
import qualified AST as A
|
import qualified AST as A
|
||||||
import CompState
|
import CompState
|
||||||
import Errors
|
import Errors
|
||||||
import EvalConstants
|
|
||||||
import EvalLiterals
|
import EvalLiterals
|
||||||
import Intrinsics
|
import Intrinsics
|
||||||
import LexOccam
|
import LexOccam
|
||||||
|
@ -596,7 +595,7 @@ newTagName = unscopedName A.TagName
|
||||||
-- | A sized array of a production.
|
-- | A sized array of a production.
|
||||||
arrayType :: OccParser A.Type -> OccParser A.Type
|
arrayType :: OccParser A.Type -> OccParser A.Type
|
||||||
arrayType element
|
arrayType element
|
||||||
= do (s, t) <- tryXVXV sLeft constIntExpr sRight element
|
= do (s, t) <- tryXVXV sLeft intExpr sRight element
|
||||||
return $ addDimensions [A.Dimension s] t
|
return $ addDimensions [A.Dimension s] t
|
||||||
|
|
||||||
-- | Either a sized or unsized array of a production.
|
-- | Either a sized or unsized array of a production.
|
||||||
|
@ -832,12 +831,9 @@ tableElems
|
||||||
return (lr, A.Array [dim] A.Byte)
|
return (lr, A.Array [dim] A.Byte)
|
||||||
<|> do m <- md
|
<|> do m <- md
|
||||||
es <- tryXVX sLeft (noTypeContext $ sepBy1 expression sComma) sRight
|
es <- tryXVX sLeft (noTypeContext $ sepBy1 expression sComma) sRight
|
||||||
-- Constant fold early, so that tables have a better chance of
|
ets <- mapM typeOfExpression es
|
||||||
-- becoming constants.
|
|
||||||
(es', _, _) <- liftM unzip3 $ sequence [constantFold e | e <- es]
|
|
||||||
ets <- mapM typeOfExpression es'
|
|
||||||
defT <- tableType m ets
|
defT <- tableType m ets
|
||||||
return (A.ArrayLiteral m (map A.ArrayElemExpr es'), defT)
|
return (A.ArrayLiteral m (map A.ArrayElemExpr es), defT)
|
||||||
<?> "table elements"
|
<?> "table elements"
|
||||||
|
|
||||||
stringLiteral :: OccParser (A.LiteralRepr, A.Dimension)
|
stringLiteral :: OccParser (A.LiteralRepr, A.Dimension)
|
||||||
|
@ -978,17 +974,6 @@ intExpr = expressionOfType A.Int <?> "integer expression"
|
||||||
booleanExpr :: OccParser A.Expression
|
booleanExpr :: OccParser A.Expression
|
||||||
booleanExpr = expressionOfType A.Bool <?> "boolean expression"
|
booleanExpr = expressionOfType A.Bool <?> "boolean expression"
|
||||||
|
|
||||||
constExprOfType :: A.Type -> OccParser A.Expression
|
|
||||||
constExprOfType wantT
|
|
||||||
= do e <- expressionOfType wantT
|
|
||||||
(e', isConst, (m,msg)) <- constantFold e
|
|
||||||
when (not isConst) $
|
|
||||||
dieReport (m,"expression is not constant (" ++ msg ++ ")")
|
|
||||||
return e'
|
|
||||||
|
|
||||||
constIntExpr :: OccParser A.Expression
|
|
||||||
constIntExpr = constExprOfType A.Int <?> "constant integer expression"
|
|
||||||
|
|
||||||
operandOfType :: A.Type -> OccParser A.Expression
|
operandOfType :: A.Type -> OccParser A.Expression
|
||||||
operandOfType wantT
|
operandOfType wantT
|
||||||
= do o <- inTypeContext (Just wantT) operand
|
= do o <- inTypeContext (Just wantT) operand
|
||||||
|
@ -1328,10 +1313,7 @@ valIsAbbrev
|
||||||
= do m <- md
|
= do m <- md
|
||||||
(n, t, e) <- do { n <- tryXVX sVAL newVariableName sIS; e <- expression; sColon; eol; t <- typeOfExpression e; return (n, t, e) }
|
(n, t, e) <- do { n <- tryXVX sVAL newVariableName sIS; e <- expression; sColon; eol; t <- typeOfExpression e; return (n, t, e) }
|
||||||
<|> do { (s, n) <- tryXVVX sVAL dataSpecifier newVariableName sIS; e <- expressionOfType s; sColon; eol; return (n, s, e) }
|
<|> do { (s, n) <- tryXVVX sVAL dataSpecifier newVariableName sIS; e <- expressionOfType s; sColon; eol; return (n, s, e) }
|
||||||
-- Do constant folding early, so that we can use names defined this
|
return $ A.Specification m n $ A.IsExpr m A.ValAbbrev t e
|
||||||
-- way as constants elsewhere.
|
|
||||||
(e', _, _) <- constantFold e
|
|
||||||
return $ A.Specification m n $ A.IsExpr m A.ValAbbrev t e'
|
|
||||||
<?> "VAL IS abbreviation"
|
<?> "VAL IS abbreviation"
|
||||||
|
|
||||||
initialIsAbbrev :: OccParser A.Specification
|
initialIsAbbrev :: OccParser A.Specification
|
||||||
|
@ -1857,7 +1839,7 @@ caseProcess
|
||||||
caseOption :: A.Type -> OccParser (A.Structured A.Option)
|
caseOption :: A.Type -> OccParser (A.Structured A.Option)
|
||||||
caseOption t
|
caseOption t
|
||||||
= do m <- md
|
= do m <- md
|
||||||
ces <- tryVX (sepBy (constExprOfType t) sComma) eol
|
ces <- tryVX (sepBy (expressionOfType t) sComma) eol
|
||||||
indent
|
indent
|
||||||
p <- process
|
p <- process
|
||||||
outdent
|
outdent
|
||||||
|
|
|
@ -45,7 +45,7 @@ rainPasses = makePassesDep' ((== FrontendRain) . csFrontend)
|
||||||
,("Uniquify variable declarations, record declared types and resolve variable names",
|
,("Uniquify variable declarations, record declared types and resolve variable names",
|
||||||
uniquifyAndResolveVars, [Prop.noInt], namesDone)
|
uniquifyAndResolveVars, [Prop.noInt], namesDone)
|
||||||
|
|
||||||
,("Fold all constant expressions", constantFoldPass, [Prop.noInt] ++ namesDone, [Prop.constantsFolded])
|
,("Fold all constant expressions", constantFoldPass, [Prop.noInt] ++ namesDone, [Prop.constantsFolded, Prop.constantsChecked])
|
||||||
,("Annotate integer literal types", annnotateIntLiteralTypes, [Prop.noInt] ++ namesDone, [Prop.intLiteralsInBounds])
|
,("Annotate integer literal types", annnotateIntLiteralTypes, [Prop.noInt] ++ namesDone, [Prop.intLiteralsInBounds])
|
||||||
|
|
||||||
,("Record inferred name types in dictionary", recordInfNameTypes, namesDone ++ [Prop.intLiteralsInBounds], [Prop.inferredTypesRecorded])
|
,("Record inferred name types in dictionary", recordInfNameTypes, namesDone ++ [Prop.intLiteralsInBounds], [Prop.inferredTypesRecorded])
|
||||||
|
|
|
@ -26,6 +26,7 @@ module Properties
|
||||||
, arraySizesDeclared
|
, arraySizesDeclared
|
||||||
, assignFlattened
|
, assignFlattened
|
||||||
, assignParRemoved
|
, assignParRemoved
|
||||||
|
, constantsChecked
|
||||||
, constantsFolded
|
, constantsFolded
|
||||||
, declarationsUnique
|
, declarationsUnique
|
||||||
, declarationTypesRecorded
|
, declarationTypesRecorded
|
||||||
|
@ -80,7 +81,7 @@ agg_namesDone :: [Property]
|
||||||
agg_namesDone = [declarationsUnique, declarationTypesRecorded, inferredTypesRecorded, declaredNamesResolved]
|
agg_namesDone = [declarationsUnique, declarationTypesRecorded, inferredTypesRecorded, declaredNamesResolved]
|
||||||
|
|
||||||
agg_typesDone :: [Property]
|
agg_typesDone :: [Property]
|
||||||
agg_typesDone = [expressionTypesChecked, inferredTypesRecorded, processTypesChecked, typesResolvedInAST, typesResolvedInState, constantsFolded]
|
agg_typesDone = [expressionTypesChecked, inferredTypesRecorded, processTypesChecked, typesResolvedInAST, typesResolvedInState, constantsFolded, constantsChecked]
|
||||||
|
|
||||||
agg_functionsGone :: [Property]
|
agg_functionsGone :: [Property]
|
||||||
agg_functionsGone = [functionCallsRemoved, functionsRemoved]
|
agg_functionsGone = [functionCallsRemoved, functionsRemoved]
|
||||||
|
@ -140,6 +141,9 @@ declarationsUnique = Property "declarationsUnique" $
|
||||||
dieP (A.nameMeta n) $ "Duplicate definition of name (names not uniquified successfully?) " ++ show (A.nameName n) ++ " with: " ++ show (A.nameMeta n')
|
dieP (A.nameMeta n) $ "Duplicate definition of name (names not uniquified successfully?) " ++ show (A.nameName n) ++ " with: " ++ show (A.nameMeta n')
|
||||||
checkDupes (n':ns)
|
checkDupes (n':ns)
|
||||||
|
|
||||||
|
constantsChecked :: Property
|
||||||
|
constantsChecked = Property "constantsChecked" checkTODO
|
||||||
|
|
||||||
constantsFolded :: Property
|
constantsFolded :: Property
|
||||||
constantsFolded = Property "constantsFolded" checkTODO
|
constantsFolded = Property "constantsFolded" checkTODO
|
||||||
|
|
||||||
|
|
7
testcases/_bad_arraysize.occ
Normal file
7
testcases/_bad_arraysize.occ
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
PROC p ()
|
||||||
|
INT x:
|
||||||
|
SEQ
|
||||||
|
x := 42
|
||||||
|
[x]INT blah:
|
||||||
|
SKIP
|
||||||
|
:
|
10
testcases/_bad_option.occ
Normal file
10
testcases/_bad_option.occ
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
PROC p ()
|
||||||
|
INT x, y:
|
||||||
|
SEQ
|
||||||
|
x, y := 42, 43
|
||||||
|
CASE x
|
||||||
|
12
|
||||||
|
SKIP
|
||||||
|
y
|
||||||
|
SKIP
|
||||||
|
:
|
Loading…
Reference in New Issue
Block a user