libcspm-0.2.0: src/CSPM/DataStructures/Syntax.hs
-- | This module represents the abstract syntax tree of machine CSP.
-- Most of the datatypes are parameterised over the type of variables that they
-- contain. Before renaming (by 'CSPM.Renamer') the variables are of type
-- 'UnRenamedName', wheras after renaming they are of type 'Name' (and are
-- hence associated with their bindings instances). Furthermore, nearly all
-- pieces of syntax are annoated with their location in the source code, and
-- (sometimes) with their type (but only after type checking). This is done
-- using the 'Annotated' datatype.
module CSPM.DataStructures.Syntax (
-- * Modules
Module(..),
-- * Declarations
Decl(..), Match(..),
-- ** Assertions
Assertion(..), Model(..), ModelOption(..), SemanticProperty(..),
-- ** Data Type Clauses
DataTypeClause(..),
-- * Expressions
Exp(..), BinaryMathsOp(..), BinaryBooleanOp(..), UnaryMathsOp(..),
UnaryBooleanOp(..),
-- ** Fields
-- | Fields occur within prefix statements. For example, if the prefix
-- was @c$x?y!z@ then there would be three fields, of type 'NonDetInput',
-- 'Input' and 'Output' respectively.
Field(..),
-- ** Statements
-- | Statements occur on the right hand side of a list comprehension, or
-- in the context of replicated operators. For example, in
-- @<... | x <- y, func(b)>@, @x <- y@ and @func(b)@ are both statements,
-- of type 'Generator' and 'Qualifier' respectively.
Stmt(..),
-- * Patterns
-- | Patterns match against values and may bind some components of the
-- values to variables.
Pat(..),
-- * Interactive Statements
-- | Interactive statements are intended to be input by an interactive
-- editor.
InteractiveStmt(..),
-- * Type Synonyms
-- | As the types are parameterised over the type of names it can be
-- laborious to type the names. Therefore, some shortcuts are provided.
AnModule(..), AnDecl(..), AnMatch(..), AnPat(..), AnExp(..), AnField(..),
AnStmt(..), AnDataTypeClause(..), AnAssertion(..), AnInteractiveStmt(..),
-- ** Pre-Renaming Types
PModule(..), PDecl(..), PMatch(..), PPat(..), PExp(..), PField(..),
PStmt(..), PDataTypeClause(..), PAssertion(..), PInteractiveStmt(..),
-- ** Post-Renaming Types
TCModule(..), TCDecl(..), TCMatch(..), TCPat(..), TCExp(..), TCField(..),
TCStmt(..), TCDataTypeClause(..), TCAssertion(..), TCInteractiveStmt(..),
-- * Helpers
getType, getSymbolTable,
) where
import CSPM.DataStructures.Literals
import CSPM.DataStructures.Names
import CSPM.DataStructures.Types
import Util.Annotated
import Util.Exception
-- P = post parsing, TC = post typechecking, An = annotated
type AnModule id = Annotated () (Module id)
-- Declarations may bind multiple names
type AnDecl id = Annotated (Maybe SymbolTable, PSymbolTable) (Decl id)
type AnMatch id = Annotated () (Match id)
type AnPat id = Annotated () (Pat id)
type AnExp id = Annotated (Maybe Type, PType) (Exp id)
type AnField id = Annotated () (Field id)
type AnStmt id = Annotated () (Stmt id)
type AnDataTypeClause id = Annotated () (DataTypeClause id)
type AnAssertion id = Annotated () (Assertion id)
type AnInteractiveStmt id = Annotated () (InteractiveStmt id)
getType :: Annotated (Maybe Type, PType) a -> Type
getType an = case fst (annotation an) of
Just t -> t
Nothing -> panic "Cannot get the type of something that is not typechecked"
getSymbolTable :: Annotated (Maybe SymbolTable, PSymbolTable) a -> SymbolTable
getSymbolTable an = case fst (annotation an) of
Just t -> t
Nothing -> panic "Cannot get the symbol table of something that is not typechecked"
type PModule = AnModule UnRenamedName
type PDecl = AnDecl UnRenamedName
type PMatch = AnMatch UnRenamedName
type PPat = AnPat UnRenamedName
type PExp = AnExp UnRenamedName
type PStmt = AnStmt UnRenamedName
type PField = AnField UnRenamedName
type PDataTypeClause = AnDataTypeClause UnRenamedName
type PAssertion = AnAssertion UnRenamedName
type PInteractiveStmt = AnInteractiveStmt UnRenamedName
type TCModule = AnModule Name
type TCDecl = AnDecl Name
type TCMatch = AnMatch Name
type TCPat = AnPat Name
type TCExp = AnExp Name
type TCField = AnField Name
type TCStmt = AnStmt Name
type TCDataTypeClause = AnDataTypeClause Name
type TCAssertion = AnAssertion Name
type TCInteractiveStmt = AnInteractiveStmt Name
-- *************************************************************************
-- Modules
-- *************************************************************************
data Module id =
GlobalModule [AnDecl id]
deriving (Eq, Show)
-- *************************************************************************
-- Expressions
-- *************************************************************************
data BinaryBooleanOp =
And
| Or
| Equals
| NotEquals
| LessThan
| GreaterThan
| LessThanEq
| GreaterThanEq
deriving (Eq, Show)
data UnaryBooleanOp =
Not
deriving (Eq, Show)
data UnaryMathsOp =
Negate
deriving (Eq, Show)
data BinaryMathsOp =
Divide | Minus | Mod | Plus | Times
deriving (Eq, Show)
-- | An expression.
data Exp id =
-- | Function application.
App {
-- | The function.
appFunction :: AnExp id,
-- | The arguments applied to the function
appArguments :: [AnExp id]
}
-- | Application of a binary boolean operator.
| BooleanBinaryOp {
booleanBinaryOpOperator :: BinaryBooleanOp,
booleanBinaryOpLeftExpression :: AnExp id,
booleanBinaryOpRightExpression :: AnExp id
}
-- | Application of a unary boolean operator.
| BooleanUnaryOp {
unaryBooleanOpOperator :: UnaryBooleanOp,
unaryBooleanExpression :: AnExp id
}
-- | List concatenation, e.g. @x^y@.
| Concat {
concatLeftList :: AnExp id,
concatRightList :: AnExp id
}
-- | Dot operator application, e.g. @c.x@.
| DotApp {
dotAppLeftArgument :: AnExp id,
dotAppRighArgument :: AnExp id
}
-- | If statements, e.g. @if cond then e1 else e2@.
| If {
-- | The condition of the if.
ifCondition :: AnExp id,
-- | The then branch.
ifThenBranch :: AnExp id,
-- The else branch.
ifElseBranch :: AnExp id
}
-- | Lambda functions, e.g. @\(x,y) \@ e(x,y)@.
| Lambda {
lambdaBindingPattern :: AnPat id,
lambdaRightHandSide :: AnExp id
}
-- | Let declarations, e.g. @let func = e1 within e2@.
| Let {
letDeclarations :: [AnDecl id],
letExpression :: AnExp id
}
-- | Literals, e.g. @true@ or @1@.
| Lit {
litLiteral :: Literal
}
-- | List literals, e.g. @<1,2,3>@.
| List {
listItems :: [AnExp id]
}
-- | List comprehensions, e.g. @<x,y | (x,y) <- e>@.
| ListComp {
listCompItems :: [AnExp id],
listCompStatements :: [AnStmt id]
}
-- | Infinite list of integers from the given value, e.g. @<1..>@.
| ListEnumFrom {
listEnumFromLowerBound :: AnExp id
}
-- | Bounded list of integers between the given values, e.g. @<1..3>@.
| ListEnumFromTo {
listEnumFromToLowerBound :: AnExp id,
listEnumFromToUpperBound :: AnExp id
}
-- | The length of the list, e.g. @#list@.
| ListLength {
listLengthExpression :: AnExp id
}
-- | Application of binary maths operator, e.g. @x+y@.
| MathsBinaryOp {
mathsBinaryOpOperator :: BinaryMathsOp,
mathsBinaryOpLeftExpression :: AnExp id,
mathsBinaryOpRightExpression :: AnExp id
}
-- | Application of unary maths operator, e.g. @-x@.
| MathsUnaryOp {
mathsUnaryOpOperator :: UnaryMathsOp,
mathsUnaryOpExpression :: AnExp id
}
-- | A user provided bracket, e.g. @(e)@.
| Paren {
parenExpression :: AnExp id
}
-- | Set literals, e.g. @{1,2,3}@.
| Set {
setItems :: [AnExp id]
}
-- | Set comprehensions, e.g. @{x,y | (x,y) <- e}@.
| SetComp {
setCompItems :: [AnExp id],
setCompStatements :: [AnStmt id]
}
-- | Enumerated Sets, i.e. sets that complete the events, e.g. @{| c.x |}@.
| SetEnum {
setEnumItems :: [AnExp id]
}
-- | Set comprehension version of 'SetEnum', e.g. @{| c.x | x <- xs |}@.
| SetEnumComp {
setEnumCompItems :: [AnExp id],
setEnumCompStatements :: [AnStmt id]
}
-- | The infinite set of integers from the given value, e.g. @{5..}@.
| SetEnumFrom {
setEnumFromLowerBound :: AnExp id
}
-- | The bounded set of integers between the two given values, e.g.
-- @{5..6}@.
| SetEnumFromTo {
-- | The lower bound.
setEnumFromToLowerBound :: AnExp id,
-- | The upper bound.
setEnumFromToUpperBound :: AnExp id
}
-- | Tuples, e.g. @(1,2)@.
| Tuple {
tupleItems :: [AnExp id]
}
-- | Variables, e.g. @x@.
| Var {
varIdentity :: id
}
-- Processes
-- | Alphabetised parallel, e.g. @P [A || B] Q@.
| AlphaParallel {
-- | Process 1.
alphaParLeftProcess :: AnExp id,
-- | Alphabet of process 1.
alphaParAlphabetLeftProcess :: AnExp id,
-- | Alphabet of process 2.
alphaParAlphabetRightProcess :: AnExp id,
-- | Process 2.
alphaParRightProcess :: AnExp id
}
-- | Exception operator, e.g. @P [| A |> Q@.
| Exception {
exceptionLeftProcess :: AnExp id,
exceptionAlphabet :: AnExp id,
exceptionRightProcess :: AnExp id
}
-- | External choice, e.g. @P [] Q@.
| ExternalChoice {
extChoiceLeftProcess :: AnExp id,
extChoiceRightOperator :: AnExp id
}
-- | Generalised parallel, e.g. @P [| A |] Q@.
| GenParallel {
genParallelLeftProcess :: AnExp id,
genParallelAlphabet :: AnExp id,
genParallelRightProcess :: AnExp id
}
-- | Guarded expressions, e.g. @b & P@ where @b@ is a boolean expression.
-- This is equivalent to @if b then P else STOP@.
| GuardedExp {
guardedExpCondition :: AnExp id,
guardedExpProcess :: AnExp id
}
-- | Hiding of events, e.g. @P \ A@.
| Hiding {
-- | The process the hiding is applied to.
hidingProcess :: AnExp id,
-- | The set of events to be hidden.
hidingAlphabet :: AnExp id
}
-- | Internal choice, e.g. @P |~| Q@.
| InternalChoice {
intChoiceLeftProcess :: AnExp id,
intChoiceRightProcess :: AnExp id
}
-- | Interrupt (where the left process is turned off once the right process
-- performs an event), e.g. @P /\ Q@.
| Interrupt {
interruptLeftProcess :: AnExp id,
interruptRightProcess :: AnExp id
}
-- | Interleaving of processes, e.g. @P ||| Q@.
| Interleave {
interleaveLeftProcess :: AnExp id,
interleaveRightProcess :: AnExp id
}
-- Linked parallel, e.g. @P [a.x <- b.x | x <- X] Q@.
| LinkParallel {
linkParLeftProcess :: AnExp id,
linkParTiedEvents :: [(AnExp id, AnExp id)],
linkParTieStatements :: [AnStmt id],
linkParRightProcess :: AnExp id
}
-- | Event prefixing, e.g. @c$x?y!z -> P@.
| Prefix {
prefixChannel :: AnExp id,
prefixFields :: [AnField id],
prefixProcess :: AnExp id
}
-- | Event renaming, e.g. @P [[ a.x <- b.x | x <- X ]]@.
| Rename {
-- | The process that is renamed.
renameProcess :: AnExp id,
-- | The events that are renamed, in the format of @(old, new)@.
renameTiedEvents :: [(AnExp id, AnExp id)],
-- | The statements for the ties.
renameTieStatements :: [AnStmt id]
}
-- | Sequential composition, e.g. @P; Q@.
| SequentialComp {
seqCompLeftProcess :: AnExp id,
seqCompRightProcess :: AnExp id
}
-- | Sliding choice, e.g. @P |> Q@.
| SlidingChoice {
slidingChoiceLeftProcess :: AnExp id,
slidingChoiceRightProcess :: AnExp id
}
-- Replicated Operators
-- | Replicated alphabetised parallel, e.g. @|| x : X \@ [| A(x) |] P(x)@.
| ReplicatedAlphaParallel {
repAlphaParReplicatedStatements :: [AnStmt id],
repAlphaParAlphabet :: AnExp id,
repAlphaParProcess :: AnExp id
}
-- | Replicated external choice, e.g. @[] x : X \@ P(x)@.
| ReplicatedExternalChoice {
repExtChoiceReplicatedStatements :: [AnStmt id],
repExtChoiceProcess :: AnExp id
}
-- | Replicated interleave, e.g. @||| x : X \@ P(x)@.
| ReplicatedInterleave {
repInterleaveReplicatedStatements :: [AnStmt id],
repInterleaveProcess :: AnExp id
}
-- | Replicated internal choice, e.g. @|~| x : X \@ P(x)@.
| ReplicatedInternalChoice {
repIntChoiceReplicatedStatements :: [AnStmt id],
repIntChoiceProcess :: AnExp id
}
-- | Replicated link parallel, e.g.
-- @[a.x <- b.x | x <- X(y)] y : Y \@ P(y)@.
| ReplicatedLinkParallel {
-- | The tied events.
repLinkParTiedChannels :: [(AnExp id, AnExp id)],
-- | The statements for the ties.
repLinkParTieStatements :: [AnStmt id],
-- | The 'Stmt's - the process (and ties) are evaluated once for each
-- value generated by these.
repLinkParReplicatedStatements :: [AnStmt id],
-- | The process
repLinkParProcess :: AnExp id
}
-- | Replicated parallel, e.g. @[| A |] x : X \@ P(x)@.
| ReplicatedParallel {
repParAlphabet :: AnExp id,
repParReplicatedStatements :: [AnStmt id],
repParProcess :: AnExp id
}
-- | Used only for parsing - never appears in an AST.
| ExpPatWildCard
-- | Used only for parsing - never appears in an AST.
| ExpPatDoublePattern (AnExp id) (AnExp id)
deriving (Eq, Show)
data Field id =
-- | @!x@
Output (AnExp id)
-- | @?x:A@
| Input (AnPat id) (Maybe (AnExp id))
-- | @$x:A@ (see P395 UCS)
| NonDetInput (AnPat id) (Maybe (AnExp id))
deriving (Eq, Show)
data Stmt id =
Generator (AnPat id) (AnExp id)
| Qualifier (AnExp id)
deriving (Eq, Show)
-- | A statement in an interactive session.
data InteractiveStmt id =
Evaluate (AnExp id)
| Bind (AnDecl id)
| RunAssertion (Assertion id)
deriving Show
-- *************************************************************************
-- Declarations
-- *************************************************************************
data Decl id =
-- | A function binding, e.g. @func(x,y)(z) = 0@.
FunBind id [AnMatch id]
-- | The binding of a pattern to an expression, e.g. @(p,q) = e@.
| PatBind (AnPat id) (AnExp id)
-- | An assertion in a file, e.g. @assert P [T= Q@.
| Assert (Assertion id)
-- | An import of an external function, e.g. @external test@,
| External {
externalImportedNames :: [id]
}
-- | An import of a transparent function, e.g. @transparent normal@.
| Transparent {
transparentImportedNames :: [id]
}
-- | A channel declaration, e.g. @channel c, d : {0..1}.{0..1}@.
| Channel [id] (Maybe (AnExp id))
-- | A datatype declaration, e.g. @datatype T = Clause1 | Clause2@.
| DataType id [AnDataTypeClause id]
-- | A nametype declaration, e.g. @nametype T2 = T.T@.
| NameType id (AnExp id)
deriving (Eq, Show)
-- TODO: annotate
data Assertion id =
-- | A refinement assertion, e.g. @assert P [F= Q@.
Refinement {
refinementSpecification :: AnExp id,
refinementModel :: Model,
refinementImplementation :: AnExp id,
refinementModelOptions :: [ModelOption id]
}
-- | A check of property, like deadlock freedom, e.g.
-- @assert P :[deadlock free [F]]@.
| PropertyCheck {
propertyCheckProcess :: AnExp id,
propertyCheckProperty :: SemanticProperty,
propertyCheckModel :: Maybe Model
}
-- | A boolean assertion, not currently supported.
| BoolAssertion (AnExp id)
-- | The negation of an assertion, not currently supported.
| ASNot (Assertion id)
deriving (Eq, Show)
data Model =
Traces
| Failures
| FailuresDivergences
| Refusals
| RefusalsDivergences
| Revivals
| RevivalsDivergences
deriving (Eq, Show)
data ModelOption id =
TauPriority (AnExp id)
deriving (Eq, Show)
data SemanticProperty =
DeadlockFreedom
| Deterministic
| LivelockFreedom
deriving (Eq, Show)
-- TODO: annotate
-- | The clause of a datatype, e.g. if a datatype declaration was:
--
-- > datatype T = A.Int.Bool | B.Bool | C
--
-- Then T would have three datatype clauses, one for each of its tags (i.e.
-- @A@, @B@ and @C@).
data DataTypeClause id =
DataTypeClause {
-- | The name of the datatype clause.
dataTypeClauseName :: id,
-- | The expression that gives the set of values that can be dotted
-- with this clause. For example, in the above example the datatype
-- clause for A would have "Int.Bool" as its type expression.
dataTypeClauseTypeExpression :: Maybe (AnExp id)
}
deriving (Eq, Show)
-- | Matches occur on the left hand side of a function declaration and there
-- is one 'Match' for each clause of the declaration. For example, given the
-- declaration:
--
-- @
-- f(<>) = 0
-- f(<x>^xs) = 1+f(xs)
-- @
--
-- there would be two matches.
data Match id =
Match {
-- | The patterns that need to be matched. This is a list of lists as
-- functions may be curried, like @f(x,y)(z) = ...@.
matchPatterns :: [[AnPat id]],
-- | The expression to be evaluated if the match succeeds.
matchRightHandSide :: AnExp id
}
deriving (Eq, Show)
data Pat id =
-- | The concatenation of two patterns, e.g. @p1^p2@.
PConcat {
pConcatLeftPat :: AnPat id,
pConcatRightPat :: AnPat id
}
-- | The dot of two patterns, e.g. @p1.p2@.
| PDotApp {
pDotLeftPat :: AnPat id,
pDotRightPat :: AnPat id
}
-- | A double pattern match, e.g. @p1\@\@p2@.
| PDoublePattern {
pDoublePatLeftPat :: AnPat id,
pDoublePatRightPat :: AnPat id
}
-- | A literal pattern list, e.g. @<p1,p2,p3>@.
| PList {
pListItems :: [AnPat id]
}
-- | A literal pattern, e.g. @true@, or @0@.
| PLit {
pLitLiteral :: Literal
}
-- | A user supplied parenthesis in a pattern.
| PParen {
pParenPattern :: AnPat id
}
-- | A set pattern. Only singleton patterns, or zero patterns are supported.
-- This is checked by the desugarer. For example, @{p1,p2}@ is not allowed,
-- but @{p1}@ and @{}@ are allowed.
| PSet {
pSetItems :: [AnPat id]
}
-- | A tuple pattern, e.g. @(p1,p2,p3)@.
| PTuple {
pTupleItems :: [AnPat id]
}
-- | A variable pattern, e.g. @x@, or @A@ where @A@ is a datatype clause.
-- If the variable is a datatype clause then it only matches that datatype
-- tag, whereas for anything else it matches anything.
| PVar {
pVarIdentity :: id
}
-- | Matches anything but does not bind it.
| PWildCard
-- | Since you can write list patterns such as:
--
-- > f(<x,y>^xs^<z,p>^<9,0>)
-- > f(<x,y>)
-- > f(xs^<x,y>)
--
-- we need an easy may of matching them. Thus, we compile
-- the patterns to a @PCompList@ instead.
--
-- @PCompList ps (Just (p, ps'))@ corresponds to a list
-- where it starts with ps (where each p in ps matches exactly one
-- list element, has a middle of p (which must be a variable pattern,
-- or a wildcard) and and end matching exactly ps' (again, where each p
-- in ps matches exactly one list component).
| PCompList {
pListStartItems :: [AnPat id],
pListMiddleEndItems :: Maybe (AnPat id, [AnPat id]),
pListOriginalPattern :: Pat id
}
-- | Like with a 'PCompList' we flatten nested dot patterns to make it
-- easier to evaluate.
| PCompDot {
pDotItems :: [AnPat id],
pDotOriginalpattern :: Pat id
}
deriving (Eq, Show)