2019-03-04 08:58:00 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
|
|
|
|
- Advanced parser for declarations and module instantiations.
|
|
|
|
|
-
|
|
|
|
|
- This module exists because the SystemVerilog grammar has conflicts which
|
|
|
|
|
- cannot be resolved by an LALR(1) parser. This module provides an interface
|
|
|
|
|
- for parsing an list of "DeclTokens" into `Decl`s and/or `ModuleItem`s. This
|
|
|
|
|
- works through a series of functions which have an greater lookahead for
|
|
|
|
|
- resolving the conflicts.
|
|
|
|
|
-
|
|
|
|
|
- Consider the following two module declarations:
|
|
|
|
|
- module Test(one two, three [1:0], four);
|
|
|
|
|
- module Test(one two, three [1:0] four);
|
|
|
|
|
-
|
|
|
|
|
- When `{one} two ,` is on the stack, it is impossible to know whether to A)
|
|
|
|
|
- shift `three` to add to the current declaration list; or B) to reduce the
|
|
|
|
|
- stack and begin a new port declaration; without looking ahead more than 1
|
|
|
|
|
- token (even ignoring the fact that a range is itself multiple tokens).
|
|
|
|
|
-
|
|
|
|
|
- While I previous had some success dealing with conflicts in the parser with
|
|
|
|
|
- increasingly convoluted grammars, this became more and more untenable as I
|
|
|
|
|
- added support for more SystemVerilog constructs.
|
|
|
|
|
-
|
2019-08-31 21:32:24 +02:00
|
|
|
- This parser is very liberal, and so accepts some syntactically invalid files.
|
|
|
|
|
- In the future, we may add some basic type-checking to complain about
|
|
|
|
|
- malformed input files. However, we generally assume that users have tested
|
|
|
|
|
- their code with a commercial simulator before running it through our tool.
|
2019-03-04 08:58:00 +01:00
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
module Language.SystemVerilog.Parser.ParseDecl
|
|
|
|
|
( DeclToken (..)
|
|
|
|
|
, parseDTsAsPortDecls
|
|
|
|
|
, parseDTsAsModuleItems
|
|
|
|
|
, parseDTsAsDecls
|
|
|
|
|
, parseDTsAsDecl
|
2019-03-04 20:25:38 +01:00
|
|
|
, parseDTsAsDeclOrAsgn
|
2019-03-27 06:53:26 +01:00
|
|
|
, parseDTsAsDeclsAndAsgns
|
2019-03-04 08:58:00 +01:00
|
|
|
) where
|
|
|
|
|
|
2019-03-27 06:53:26 +01:00
|
|
|
import Data.List (elemIndex, findIndex, findIndices)
|
|
|
|
|
import Data.Maybe (fromJust, mapMaybe)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
import Language.SystemVerilog.AST
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: combined (irregular) tokens for declarations
|
|
|
|
|
data DeclToken
|
|
|
|
|
= DTComma
|
2019-03-07 21:56:03 +01:00
|
|
|
| DTAsgn AsgnOp Expr
|
2019-03-22 07:47:25 +01:00
|
|
|
| DTAsgnNBlk (Maybe Timing) Expr
|
2019-04-09 04:02:49 +02:00
|
|
|
| DTRange (PartSelectMode, Range)
|
2019-03-04 08:58:00 +01:00
|
|
|
| DTIdent Identifier
|
2019-04-24 09:37:47 +02:00
|
|
|
| DTPSIdent Identifier Identifier
|
2019-03-04 08:58:00 +01:00
|
|
|
| DTDir Direction
|
2019-03-22 21:57:13 +01:00
|
|
|
| DTType (Signing -> [Range] -> Type)
|
2019-03-04 08:58:00 +01:00
|
|
|
| DTParams [PortBinding]
|
2019-03-25 23:53:55 +01:00
|
|
|
| DTInstance [PortBinding]
|
2019-03-04 20:25:38 +01:00
|
|
|
| DTBit Expr
|
|
|
|
|
| DTConcat [LHS]
|
2019-09-03 02:46:35 +02:00
|
|
|
| DTStream StreamOp Expr [LHS]
|
2019-03-08 22:26:47 +01:00
|
|
|
| DTDot Identifier
|
2019-03-22 21:57:13 +01:00
|
|
|
| DTSigning Signing
|
2019-08-31 21:32:24 +02:00
|
|
|
| DTLifetime Lifetime
|
2019-03-04 08:58:00 +01:00
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
|
|
|
|
|
2019-03-08 20:47:20 +01:00
|
|
|
-- entrypoints besides `parseDTsAsDeclOrAsgn` use this to disallow `DTAsgnNBlk`
|
|
|
|
|
-- and `DTAsgn` with a binary assignment operator because we don't expect to see
|
|
|
|
|
-- those assignment oeprators in declarations
|
|
|
|
|
forbidNonEqAsgn :: [DeclToken] -> a -> a
|
|
|
|
|
forbidNonEqAsgn tokens =
|
|
|
|
|
if any isNonEqAsgn tokens
|
|
|
|
|
then error $ "decl tokens contain bad assignment operator: " ++ show tokens
|
|
|
|
|
else id
|
|
|
|
|
where
|
|
|
|
|
isNonEqAsgn :: DeclToken -> Bool
|
2019-03-22 07:47:25 +01:00
|
|
|
isNonEqAsgn (DTAsgnNBlk _ _) = True
|
2019-03-08 20:47:20 +01:00
|
|
|
isNonEqAsgn (DTAsgn (AsgnOp _) _) = True
|
|
|
|
|
isNonEqAsgn _ = False
|
|
|
|
|
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
-- [PUBLIC]: parser for module port declarations, including interface ports
|
|
|
|
|
-- Example: `input foo, bar, One inst`
|
|
|
|
|
parseDTsAsPortDecls :: [DeclToken] -> ([Identifier], [ModuleItem])
|
|
|
|
|
parseDTsAsPortDecls pieces =
|
2019-03-08 20:47:20 +01:00
|
|
|
forbidNonEqAsgn pieces $
|
2019-03-04 08:58:00 +01:00
|
|
|
if isSimpleList
|
|
|
|
|
then (simpleIdents, [])
|
2019-04-23 23:12:56 +02:00
|
|
|
else (portNames declarations, map (MIPackageItem . Decl) declarations)
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
|
|
|
|
commaIdxs = findIndices isComma pieces
|
|
|
|
|
identIdxs = findIndices isIdent pieces
|
|
|
|
|
isSimpleList =
|
|
|
|
|
all even identIdxs &&
|
|
|
|
|
all odd commaIdxs &&
|
|
|
|
|
odd (length pieces) &&
|
|
|
|
|
length pieces == length commaIdxs + length identIdxs
|
|
|
|
|
|
|
|
|
|
simpleIdents = map extractIdent $ filter isIdent pieces
|
|
|
|
|
declarations = parseDTsAsDecls pieces
|
|
|
|
|
|
|
|
|
|
isComma :: DeclToken -> Bool
|
|
|
|
|
isComma token = token == DTComma
|
|
|
|
|
extractIdent = \(DTIdent x) -> x
|
|
|
|
|
|
|
|
|
|
portNames :: [Decl] -> [Identifier]
|
|
|
|
|
portNames items = mapMaybe portName items
|
|
|
|
|
portName :: Decl -> Maybe Identifier
|
|
|
|
|
portName (Variable _ _ ident _ _) = Just ident
|
|
|
|
|
portName decl =
|
|
|
|
|
error $ "unexpected non-variable port declaration: " ++ (show decl)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: parser for single (semicolon-terminated) declarations (including
|
|
|
|
|
-- parameters) and module instantiations
|
|
|
|
|
parseDTsAsModuleItems :: [DeclToken] -> [ModuleItem]
|
|
|
|
|
parseDTsAsModuleItems tokens =
|
2019-03-08 20:47:20 +01:00
|
|
|
forbidNonEqAsgn tokens $
|
2019-03-04 08:58:00 +01:00
|
|
|
if any isInstance tokens
|
|
|
|
|
then parseDTsAsIntantiations tokens
|
2019-04-23 23:12:56 +02:00
|
|
|
else map (MIPackageItem . Decl) $ parseDTsAsDecl tokens
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
|
|
|
|
isInstance :: DeclToken -> Bool
|
|
|
|
|
isInstance (DTInstance _) = True
|
|
|
|
|
isInstance _ = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- internal; parser for module instantiations
|
|
|
|
|
parseDTsAsIntantiations :: [DeclToken] -> [ModuleItem]
|
|
|
|
|
parseDTsAsIntantiations (DTIdent name : tokens) =
|
2019-03-25 23:53:55 +01:00
|
|
|
if not (all isInstanceToken rest)
|
2019-03-04 08:58:00 +01:00
|
|
|
then error $ "instantiations mixed with other items: " ++ (show rest)
|
2019-03-25 23:53:55 +01:00
|
|
|
else step rest
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
2019-03-25 23:53:55 +01:00
|
|
|
step :: [DeclToken] -> [ModuleItem]
|
|
|
|
|
step [] = error $ "unexpected end of instantiation list: " ++ (show tokens)
|
|
|
|
|
step toks =
|
|
|
|
|
Instance name params x mr p : follow
|
|
|
|
|
where
|
|
|
|
|
(inst, toks') = span (DTComma /=) toks
|
|
|
|
|
(x, mr, p) = case inst of
|
2019-04-09 04:02:49 +02:00
|
|
|
[DTIdent a, DTRange (NonIndexed, s), DTInstance b] ->
|
|
|
|
|
(a, Just s , b)
|
|
|
|
|
[DTIdent a, DTInstance b] -> (a, Nothing, b)
|
2019-03-25 23:53:55 +01:00
|
|
|
_ -> error $ "unrecognized instantiation: " ++ show inst
|
|
|
|
|
follow = x `seq` if null toks' then [] else step (tail toks')
|
2019-03-04 08:58:00 +01:00
|
|
|
(params, rest) =
|
|
|
|
|
case head tokens of
|
|
|
|
|
DTParams ps -> (ps, tail tokens)
|
|
|
|
|
_ -> ([], tokens)
|
2019-03-25 23:53:55 +01:00
|
|
|
isInstanceToken :: DeclToken -> Bool
|
|
|
|
|
isInstanceToken (DTInstance _) = True
|
|
|
|
|
isInstanceToken (DTRange _) = True
|
|
|
|
|
isInstanceToken (DTIdent _) = True
|
|
|
|
|
isInstanceToken DTComma = True
|
|
|
|
|
isInstanceToken _ = False
|
2019-03-04 08:58:00 +01:00
|
|
|
parseDTsAsIntantiations tokens =
|
|
|
|
|
error $
|
|
|
|
|
"DeclTokens contain instantiations, but start with non-ident: "
|
|
|
|
|
++ (show tokens)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: parser for generic, comma-separated declarations
|
|
|
|
|
parseDTsAsDecls :: [DeclToken] -> [Decl]
|
|
|
|
|
parseDTsAsDecls tokens =
|
2019-03-08 20:47:20 +01:00
|
|
|
forbidNonEqAsgn tokens $
|
2019-03-04 08:58:00 +01:00
|
|
|
concat $ map finalize $ parseDTsAsComponents tokens
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: used for "single" declarations, i.e., declarations appearing
|
|
|
|
|
-- outside of a port list
|
|
|
|
|
parseDTsAsDecl :: [DeclToken] -> [Decl]
|
|
|
|
|
parseDTsAsDecl tokens =
|
2019-03-08 20:47:20 +01:00
|
|
|
forbidNonEqAsgn tokens $
|
2019-03-04 08:58:00 +01:00
|
|
|
if length components /= 1
|
|
|
|
|
then error $ "too many declarations: " ++ (show tokens)
|
|
|
|
|
else finalize $ head components
|
|
|
|
|
where components = parseDTsAsComponents tokens
|
|
|
|
|
|
|
|
|
|
|
2019-03-05 02:58:09 +01:00
|
|
|
-- [PUBLIC]: parser for single block item declarations or assign or arg-less
|
|
|
|
|
-- subroutine call statetments
|
2019-03-04 20:25:38 +01:00
|
|
|
parseDTsAsDeclOrAsgn :: [DeclToken] -> ([Decl], [Stmt])
|
2019-04-24 09:37:47 +02:00
|
|
|
parseDTsAsDeclOrAsgn [DTIdent f] = ([], [Subroutine (Nothing) f (Args [] [])])
|
|
|
|
|
parseDTsAsDeclOrAsgn [DTPSIdent p f] = ([], [Subroutine (Just p) f (Args [] [])])
|
2019-03-04 20:25:38 +01:00
|
|
|
parseDTsAsDeclOrAsgn tokens =
|
2019-09-02 00:40:24 +02:00
|
|
|
if (any isAsgnToken tokens || tripLookahead tokens) && lhs /= Nothing
|
|
|
|
|
then ([], [constructor (fromJust lhs) expr])
|
2019-03-04 20:25:38 +01:00
|
|
|
else (parseDTsAsDecl tokens, [])
|
|
|
|
|
where
|
|
|
|
|
(constructor, expr) = case last tokens of
|
2019-03-22 07:47:25 +01:00
|
|
|
DTAsgn op e -> (AsgnBlk op, e)
|
|
|
|
|
DTAsgnNBlk mt e -> (Asgn mt, e)
|
2019-03-04 20:25:38 +01:00
|
|
|
_ -> error $ "invalid block item decl or stmt: " ++ (show tokens)
|
2019-03-27 06:53:26 +01:00
|
|
|
lhs = takeLHS $ init tokens
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: parser for mixed comma-separated declaration and assignment lists;
|
|
|
|
|
-- the main use case is for `for` loop initialization lists
|
|
|
|
|
parseDTsAsDeclsAndAsgns :: [DeclToken] -> [Either Decl (LHS, Expr)]
|
|
|
|
|
parseDTsAsDeclsAndAsgns [] = []
|
|
|
|
|
parseDTsAsDeclsAndAsgns tokens =
|
2019-03-27 08:33:28 +01:00
|
|
|
if hasLeadingAsgn || tripLookahead tokens
|
2019-03-27 06:53:26 +01:00
|
|
|
then
|
2019-03-27 08:33:28 +01:00
|
|
|
let (lhsToks, l0) = break isDTAsgn tokens
|
2019-09-02 00:40:24 +02:00
|
|
|
lhs = case takeLHS lhsToks of
|
|
|
|
|
Nothing ->
|
|
|
|
|
error $ "could not parse as LHS: " ++ show lhsToks
|
|
|
|
|
Just l -> l
|
2019-03-27 08:33:28 +01:00
|
|
|
DTAsgn AsgnOpEq expr : l1 = l0
|
|
|
|
|
asgn = Right (lhs, expr)
|
|
|
|
|
in case l1 of
|
|
|
|
|
DTComma : remaining -> asgn : parseDTsAsDeclsAndAsgns remaining
|
|
|
|
|
[] -> [asgn]
|
|
|
|
|
_ -> error $ "bad decls and asgns tokens: " ++ show tokens
|
2019-03-27 06:53:26 +01:00
|
|
|
else
|
|
|
|
|
let (component, remaining) = parseDTsAsComponent tokens
|
|
|
|
|
decls = finalize component
|
|
|
|
|
in (map Left decls) ++ parseDTsAsDeclsAndAsgns remaining
|
|
|
|
|
where
|
|
|
|
|
hasLeadingAsgn =
|
|
|
|
|
-- if there is an asgn token before the next comma
|
|
|
|
|
case (elemIndex DTComma tokens, findIndex isAsgnToken tokens) of
|
|
|
|
|
(Just a, Just b) -> a > b
|
|
|
|
|
(Nothing, Just _) -> True
|
|
|
|
|
_ -> False
|
2019-03-27 08:33:28 +01:00
|
|
|
isDTAsgn :: DeclToken -> Bool
|
|
|
|
|
isDTAsgn (DTAsgn _ _) = True
|
|
|
|
|
isDTAsgn _ = False
|
2019-03-27 06:53:26 +01:00
|
|
|
|
|
|
|
|
isAsgnToken :: DeclToken -> Bool
|
|
|
|
|
isAsgnToken (DTBit _) = True
|
|
|
|
|
isAsgnToken (DTConcat _) = True
|
2019-09-03 02:46:35 +02:00
|
|
|
isAsgnToken (DTStream _ _ _) = True
|
2019-03-30 06:56:57 +01:00
|
|
|
isAsgnToken (DTDot _) = True
|
2019-03-27 06:53:26 +01:00
|
|
|
isAsgnToken (DTAsgnNBlk _ _) = True
|
|
|
|
|
isAsgnToken (DTAsgn (AsgnOp _) _) = True
|
|
|
|
|
isAsgnToken _ = False
|
|
|
|
|
|
2019-09-02 00:40:24 +02:00
|
|
|
takeLHS :: [DeclToken] -> Maybe LHS
|
|
|
|
|
takeLHS [] = Nothing
|
|
|
|
|
takeLHS (t : ts) =
|
|
|
|
|
foldl takeLHSStep (takeLHSStart t) ts
|
|
|
|
|
|
|
|
|
|
takeLHSStart :: DeclToken -> Maybe LHS
|
2019-09-03 02:46:35 +02:00
|
|
|
takeLHSStart (DTConcat lhss) = Just $ LHSConcat lhss
|
|
|
|
|
takeLHSStart (DTStream o e lhss) = Just $ LHSStream o e lhss
|
|
|
|
|
takeLHSStart (DTIdent x ) = Just $ LHSIdent x
|
2019-09-02 00:40:24 +02:00
|
|
|
takeLHSStart _ = Nothing
|
2019-03-04 20:25:38 +01:00
|
|
|
|
2019-03-04 21:16:53 +01:00
|
|
|
takeLHSStep :: Maybe LHS -> DeclToken -> Maybe LHS
|
|
|
|
|
takeLHSStep (Just curr) (DTBit e ) = Just $ LHSBit curr e
|
2019-04-09 04:02:49 +02:00
|
|
|
takeLHSStep (Just curr) (DTRange (m,r)) = Just $ LHSRange curr m r
|
2019-03-08 22:26:47 +01:00
|
|
|
takeLHSStep (Just curr) (DTDot x ) = Just $ LHSDot curr x
|
2019-09-02 00:40:24 +02:00
|
|
|
takeLHSStep _ _ = Nothing
|
2019-03-04 20:25:38 +01:00
|
|
|
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
-- batches together seperate declaration lists
|
|
|
|
|
type Triplet = (Identifier, [Range], Maybe Expr)
|
|
|
|
|
type Component = (Direction, Type, [Triplet])
|
|
|
|
|
finalize :: Component -> [Decl]
|
|
|
|
|
finalize (dir, typ, trips) =
|
|
|
|
|
map (\(x, a, me) -> Variable dir typ x a me) trips
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- internal; entrypoint of the critical portion of our parser
|
|
|
|
|
parseDTsAsComponents :: [DeclToken] -> [Component]
|
|
|
|
|
parseDTsAsComponents [] = []
|
2019-03-27 06:53:26 +01:00
|
|
|
parseDTsAsComponents tokens =
|
|
|
|
|
component : parseDTsAsComponents tokens'
|
|
|
|
|
where
|
|
|
|
|
(component, tokens') = parseDTsAsComponent tokens
|
|
|
|
|
|
|
|
|
|
parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken])
|
|
|
|
|
parseDTsAsComponent [] = error "parseDTsAsComponent unexpected end of tokens"
|
|
|
|
|
parseDTsAsComponent l0 =
|
2019-08-31 21:32:24 +02:00
|
|
|
if l /= Nothing && l /= Just Automatic
|
|
|
|
|
then error $ "unexpected non-automatic lifetime: " ++ show l0
|
|
|
|
|
else (component, l5)
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
2019-08-31 21:32:24 +02:00
|
|
|
(dir, l1) = takeDir l0
|
|
|
|
|
(l , l2) = takeLifetime l1
|
|
|
|
|
(tf , l3) = takeType l2
|
|
|
|
|
(rs , l4) = takeRanges l3
|
|
|
|
|
(tps, l5) = takeTrips l4 True
|
2019-03-04 08:58:00 +01:00
|
|
|
component = (dir, tf rs, tps)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
takeTrips :: [DeclToken] -> Bool -> ([Triplet], [DeclToken])
|
|
|
|
|
takeTrips [] True = error "incomplete declaration"
|
|
|
|
|
takeTrips [] False = ([], [])
|
|
|
|
|
takeTrips l0 force =
|
|
|
|
|
if not force && not (tripLookahead l0)
|
|
|
|
|
then ([], l0)
|
|
|
|
|
else (trip : trips, l5)
|
|
|
|
|
where
|
|
|
|
|
(x , l1) = takeIdent l0
|
|
|
|
|
(a , l2) = takeRanges l1
|
|
|
|
|
(me, l3) = takeAsgn l2
|
|
|
|
|
(_ , l4) = takeComma l3
|
|
|
|
|
trip = (x, a, me)
|
|
|
|
|
(trips, l5) = takeTrips l4 False
|
|
|
|
|
|
|
|
|
|
tripLookahead :: [DeclToken] -> Bool
|
|
|
|
|
tripLookahead [] = False
|
|
|
|
|
tripLookahead l0 =
|
|
|
|
|
-- every triplet *must* begin with an identifier
|
|
|
|
|
if not (isIdent $ head l0) then
|
|
|
|
|
False
|
|
|
|
|
-- if the identifier is the last token, or if it assigned a value, then we
|
|
|
|
|
-- know we must have a valid triplet ahead
|
|
|
|
|
else if null l1 || asgn /= Nothing then
|
|
|
|
|
True
|
|
|
|
|
-- if there is a comma after the identifier (and optional ranges and
|
|
|
|
|
-- assignment) that we're looking at, then we know this identifier is not a
|
|
|
|
|
-- type name, as type names must be followed by a first identifier before a
|
|
|
|
|
-- comma or the end of the list
|
|
|
|
|
else
|
|
|
|
|
(not $ null l3) && (head l3 == DTComma)
|
|
|
|
|
where
|
|
|
|
|
(_ , l1) = takeIdent l0
|
|
|
|
|
(_ , l2) = takeRanges l1
|
|
|
|
|
(asgn, l3) = takeAsgn l2
|
|
|
|
|
|
|
|
|
|
takeDir :: [DeclToken] -> (Direction, [DeclToken])
|
|
|
|
|
takeDir (DTDir dir : rest) = (dir , rest)
|
|
|
|
|
takeDir rest = (Local, rest)
|
|
|
|
|
|
2019-08-31 21:32:24 +02:00
|
|
|
takeLifetime :: [DeclToken] -> (Maybe Lifetime, [DeclToken])
|
|
|
|
|
takeLifetime (DTLifetime l : rest) = (Just l, rest)
|
|
|
|
|
takeLifetime rest = (Nothing, rest)
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
takeType :: [DeclToken] -> ([Range] -> Type, [DeclToken])
|
2019-03-22 21:57:13 +01:00
|
|
|
takeType (DTIdent a : DTDot b : rest) = (InterfaceT a (Just b), rest)
|
|
|
|
|
takeType (DTType tf : DTSigning sg : rest) = (tf sg , rest)
|
|
|
|
|
takeType (DTType tf : rest) = (tf Unspecified, rest)
|
|
|
|
|
takeType (DTSigning sg : rest) = (Implicit sg , rest)
|
|
|
|
|
takeType (DTIdent tn : DTComma : rest) = (Implicit Unspecified, DTIdent tn : DTComma : rest)
|
|
|
|
|
takeType (DTIdent tn : [ ]) = (Implicit Unspecified, DTIdent tn : [ ])
|
2019-04-24 09:37:47 +02:00
|
|
|
takeType (DTIdent tn : rest) = (Alias (Nothing) tn , rest)
|
|
|
|
|
takeType (DTPSIdent ps tn : rest) = (Alias (Just ps) tn , rest)
|
2019-03-22 21:57:13 +01:00
|
|
|
takeType rest = (Implicit Unspecified, rest)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
takeRanges :: [DeclToken] -> ([Range], [DeclToken])
|
2019-03-07 07:38:42 +01:00
|
|
|
takeRanges [] = ([], [])
|
|
|
|
|
takeRanges (token : tokens) =
|
|
|
|
|
case token of
|
2019-04-09 04:02:49 +02:00
|
|
|
DTRange (NonIndexed, r) -> (r : rs, rest )
|
|
|
|
|
DTBit s -> (asRange s : rs, rest )
|
|
|
|
|
_ -> ([] , token : tokens)
|
2019-03-07 07:38:42 +01:00
|
|
|
where
|
|
|
|
|
(rs, rest) = takeRanges tokens
|
|
|
|
|
asRange s = (simplify $ BinOp Sub s (Number "1"), Number "0")
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2019-03-08 20:47:20 +01:00
|
|
|
-- Matching DTAsgnNBlk here allows tripLookahead to work both for standard
|
|
|
|
|
-- declarations and in `parseDTsAsDeclOrAsgn`, where we're checking for an
|
|
|
|
|
-- assignment assignment statement. The other entry points disallow
|
|
|
|
|
-- `DTAsgnNBlk`, so this doesn't liberalize the parser.
|
2019-03-04 08:58:00 +01:00
|
|
|
takeAsgn :: [DeclToken] -> (Maybe Expr, [DeclToken])
|
2019-03-07 21:56:03 +01:00
|
|
|
takeAsgn (DTAsgn AsgnOpEq e : rest) = (Just e , rest)
|
2019-03-22 07:47:25 +01:00
|
|
|
takeAsgn (DTAsgnNBlk _ e : rest) = (Just e , rest)
|
2019-03-04 20:25:38 +01:00
|
|
|
takeAsgn rest = (Nothing, rest)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
takeComma :: [DeclToken] -> (Bool, [DeclToken])
|
|
|
|
|
takeComma [] = (False, [])
|
|
|
|
|
takeComma (DTComma : rest) = (True, rest)
|
2019-04-09 04:02:49 +02:00
|
|
|
takeComma toks = error $ "expected comma or end of decl, got: " ++ show toks
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
takeIdent :: [DeclToken] -> (Identifier, [DeclToken])
|
|
|
|
|
takeIdent (DTIdent x : rest) = (x, rest)
|
2019-03-07 21:39:19 +01:00
|
|
|
takeIdent tokens = error $ "takeIdent didn't find identifier: " ++ show tokens
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
isIdent :: DeclToken -> Bool
|
|
|
|
|
isIdent (DTIdent _) = True
|
|
|
|
|
isIdent _ = False
|