2020-07-09 01:46:37 +02:00
|
|
|
{-# LANGUAGE PatternSynonyms #-}
|
2019-03-04 08:58:00 +01:00
|
|
|
{- sv2v
|
|
|
|
|
- Author: Zachary Snow <zach@zachjs.com>
|
|
|
|
|
-
|
2020-01-31 04:17:17 +01:00
|
|
|
- Advanced parser for declarations, module instantiations, and some statements.
|
2019-03-04 08:58:00 +01:00
|
|
|
-
|
2020-01-31 04:17:17 +01:00
|
|
|
- This module exists because the SystemVerilog grammar is not LALR(1), and
|
|
|
|
|
- Happy can only produce LALR(1) parsers. This module provides an interface for
|
|
|
|
|
- parsing a list of "DeclTokens" into `Decl`s, `ModuleItem`s, or `Stmt`s. This
|
|
|
|
|
- works through a series of functions which have use a greater lookahead for
|
2019-03-04 08:58:00 +01:00
|
|
|
- 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
|
2020-01-31 04:17:17 +01:00
|
|
|
- token.
|
2019-03-04 08:58:00 +01:00
|
|
|
-
|
2020-01-31 04:17:17 +01:00
|
|
|
- While I previously had some success dealing with these conflicts with
|
2019-03-04 08:58:00 +01:00
|
|
|
- increasingly convoluted grammars, this became more and more untenable as I
|
|
|
|
|
- added support for more SystemVerilog constructs.
|
|
|
|
|
-
|
2020-01-31 04:17:17 +01:00
|
|
|
- Because declarations and statements are subject to the same kind of
|
|
|
|
|
- conflicts, this module additionally provides an interface for parsing
|
|
|
|
|
- DeclTokens as either declarations or the basic statements (either assignments
|
|
|
|
|
- or task/function calls) with which they can conflict. The initialization
|
|
|
|
|
- portion of a for loop also allows for declarations and assignments, and so a
|
|
|
|
|
- similar interface is provided for this case.
|
|
|
|
|
-
|
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
|
2020-01-31 04:17:17 +01:00
|
|
|
, parseDTsAsDeclOrStmt
|
2019-10-01 05:03:55 +02:00
|
|
|
, parseDTsAsDeclsOrAsgns
|
2019-03-04 08:58:00 +01:00
|
|
|
) where
|
|
|
|
|
|
2021-07-03 19:23:33 +02:00
|
|
|
import Data.List (findIndex, findIndices, partition, uncons)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
import Language.SystemVerilog.AST
|
2020-01-31 04:17:17 +01:00
|
|
|
import Language.SystemVerilog.Parser.Tokens (Position(..))
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
-- [PUBLIC]: combined (irregular) tokens for declarations
|
|
|
|
|
data DeclToken
|
2020-01-31 04:17:17 +01:00
|
|
|
= DTComma Position
|
|
|
|
|
| DTAutoDim Position
|
2021-07-02 23:59:21 +02:00
|
|
|
| DTConst Position
|
|
|
|
|
| DTVar Position
|
2020-02-01 21:52:52 +01:00
|
|
|
| DTAsgn Position AsgnOp (Maybe Timing) Expr
|
2020-01-31 04:17:17 +01:00
|
|
|
| DTRange Position (PartSelectMode, Range)
|
2020-07-10 05:01:18 +02:00
|
|
|
| DTIdent Position Identifier
|
|
|
|
|
| DTPSIdent Position Identifier Identifier
|
2020-07-09 01:46:37 +02:00
|
|
|
| DTCSIdent Position Identifier [ParamBinding] Identifier
|
2020-01-31 04:17:17 +01:00
|
|
|
| DTDir Position Direction
|
|
|
|
|
| DTType Position (Signing -> [Range] -> Type)
|
2021-07-02 23:59:21 +02:00
|
|
|
| DTNet Position NetType Strength
|
2020-01-31 04:17:17 +01:00
|
|
|
| DTParams Position [ParamBinding]
|
2021-07-03 19:23:33 +02:00
|
|
|
| DTPorts Position [PortBinding]
|
2020-01-31 04:17:17 +01:00
|
|
|
| DTBit Position Expr
|
|
|
|
|
| DTConcat Position [LHS]
|
|
|
|
|
| DTStream Position StreamOp Expr [LHS]
|
|
|
|
|
| DTDot Position Identifier
|
|
|
|
|
| DTSigning Position Signing
|
|
|
|
|
| DTLifetime Position Lifetime
|
2020-12-08 19:28:28 +01:00
|
|
|
| DTAttr Position Attr
|
2019-03-04 08:58:00 +01:00
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
2020-02-01 21:52:52 +01:00
|
|
|
-- entrypoints besides `parseDTsAsDeclOrStmt` use this to disallow `DTAsgn` with
|
|
|
|
|
-- a non-blocking operator, binary assignment operator, or a timing control
|
|
|
|
|
-- because we don't expect to see those assignment operators in declarations
|
2019-03-08 20:47:20 +01:00
|
|
|
forbidNonEqAsgn :: [DeclToken] -> a -> a
|
2021-07-03 19:23:33 +02:00
|
|
|
forbidNonEqAsgn [] = id
|
|
|
|
|
forbidNonEqAsgn (tok @ (DTAsgn _ op mt _) : toks) =
|
|
|
|
|
if op /= AsgnOpEq then
|
|
|
|
|
parseError tok $ "unexpected " ++ opKind
|
|
|
|
|
++ " assignment operator in declaration"
|
|
|
|
|
else if mt /= Nothing then
|
|
|
|
|
parseError tok "unexpected timing modifier in declaration"
|
|
|
|
|
else
|
|
|
|
|
forbidNonEqAsgn toks
|
|
|
|
|
where opKind = if op == AsgnOpNonBlocking then "non-blocking" else "binary"
|
|
|
|
|
forbidNonEqAsgn (_ : toks) = forbidNonEqAsgn toks
|
2019-03-08 20:47:20 +01:00
|
|
|
|
|
|
|
|
|
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 =
|
2021-04-23 22:06:57 +02:00
|
|
|
parseDTsAsPortDecls' $
|
|
|
|
|
case last pieces of
|
|
|
|
|
DTComma{} -> init pieces
|
|
|
|
|
_ -> pieces
|
|
|
|
|
|
|
|
|
|
-- internal parseDTsAsPortDecls after the removal of an optional trailing comma
|
|
|
|
|
parseDTsAsPortDecls' :: [DeclToken] -> ([Identifier], [ModuleItem])
|
|
|
|
|
parseDTsAsPortDecls' pieces =
|
2021-07-03 19:23:33 +02:00
|
|
|
forbidNonEqAsgn pieces `seq`
|
2019-03-04 08:58:00 +01:00
|
|
|
if isSimpleList
|
|
|
|
|
then (simpleIdents, [])
|
2020-12-08 19:28:28 +01:00
|
|
|
else (portNames declarations, applyAttrs [] pieces 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
|
2020-12-08 19:28:28 +01:00
|
|
|
declarations = propagateDirections Input $ parseDTsAsDecls pieces'
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2020-01-31 04:17:17 +01:00
|
|
|
extractIdent = \(DTIdent _ x) -> x
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2020-12-08 19:28:28 +01:00
|
|
|
pieces' = filter (not . isDTAttr) pieces
|
|
|
|
|
isDTAttr :: DeclToken -> Bool
|
|
|
|
|
isDTAttr DTAttr{} = True
|
|
|
|
|
isDTAttr _ = False
|
|
|
|
|
|
2020-02-09 03:14:03 +01:00
|
|
|
propagateDirections :: Direction -> [Decl] -> [Decl]
|
|
|
|
|
propagateDirections dir (decl @ (Variable _ InterfaceT{} _ _ _) : decls) =
|
|
|
|
|
decl : propagateDirections dir decls
|
2020-06-14 21:56:09 +02:00
|
|
|
propagateDirections lastDir (Variable currDir t x a e : decls) =
|
2020-02-09 03:14:03 +01:00
|
|
|
decl : propagateDirections dir decls
|
|
|
|
|
where
|
2020-06-14 21:56:09 +02:00
|
|
|
decl = Variable dir t x a e
|
2020-02-09 03:14:03 +01:00
|
|
|
dir = if currDir == Local then lastDir else currDir
|
2021-07-02 23:59:21 +02:00
|
|
|
propagateDirections lastDir (Net currDir n s t x a e : decls) =
|
|
|
|
|
decl : propagateDirections dir decls
|
|
|
|
|
where
|
|
|
|
|
decl = Net dir n s t x a e
|
|
|
|
|
dir = if currDir == Local then lastDir else currDir
|
2020-02-09 03:14:03 +01:00
|
|
|
propagateDirections dir (decl : decls) =
|
|
|
|
|
decl : propagateDirections dir decls
|
|
|
|
|
propagateDirections _ [] = []
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
portNames :: [Decl] -> [Identifier]
|
2020-06-14 21:56:09 +02:00
|
|
|
portNames = filter (not . null) . map portName
|
|
|
|
|
portName :: Decl -> Identifier
|
|
|
|
|
portName (Variable _ _ ident _ _) = ident
|
2021-07-02 23:59:21 +02:00
|
|
|
portName (Net _ _ _ _ ident _ _) = ident
|
2020-06-14 21:56:09 +02:00
|
|
|
portName CommentDecl{} = ""
|
2019-03-04 08:58:00 +01:00
|
|
|
portName decl =
|
|
|
|
|
error $ "unexpected non-variable port declaration: " ++ (show decl)
|
|
|
|
|
|
2020-12-08 19:28:28 +01:00
|
|
|
applyAttrs :: [Attr] -> [DeclToken] -> [Decl] -> [ModuleItem]
|
|
|
|
|
applyAttrs _ [] [] = []
|
|
|
|
|
applyAttrs _ tokens (CommentDecl c : decls) =
|
|
|
|
|
MIPackageItem (Decl $ CommentDecl c) : applyAttrs [] tokens decls
|
|
|
|
|
applyAttrs attrs (DTAttr _ attr : tokens) decls =
|
|
|
|
|
applyAttrs (attr : attrs) tokens decls
|
|
|
|
|
applyAttrs attrs [] [decl] =
|
|
|
|
|
[wrapDecl attrs decl]
|
|
|
|
|
applyAttrs attrs (DTComma{} : tokens) (decl : decls) =
|
|
|
|
|
wrapDecl attrs decl : applyAttrs attrs tokens decls
|
|
|
|
|
applyAttrs attrs (_ : tokens) decls =
|
|
|
|
|
applyAttrs attrs tokens decls
|
|
|
|
|
applyAttrs _ [] _ = error "applyAttrs internal invariant failed"
|
|
|
|
|
|
|
|
|
|
wrapDecl :: [Attr] -> Decl -> ModuleItem
|
|
|
|
|
wrapDecl attrs decl = foldr MIAttr (MIPackageItem $ Decl decl) attrs
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
-- [PUBLIC]: parser for single (semicolon-terminated) declarations (including
|
|
|
|
|
-- parameters) and module instantiations
|
|
|
|
|
parseDTsAsModuleItems :: [DeclToken] -> [ModuleItem]
|
|
|
|
|
parseDTsAsModuleItems tokens =
|
2021-07-03 19:23:33 +02:00
|
|
|
forbidNonEqAsgn tokens `seq`
|
2019-09-18 02:30:17 +02:00
|
|
|
if isElabTask $ head tokens then
|
|
|
|
|
asElabTask tokens
|
2021-07-03 19:23:33 +02:00
|
|
|
else if any isPorts tokens then
|
2019-09-18 02:30:17 +02:00
|
|
|
parseDTsAsIntantiations tokens
|
|
|
|
|
else
|
|
|
|
|
map (MIPackageItem . Decl) $ parseDTsAsDecl tokens
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
2019-09-18 02:30:17 +02:00
|
|
|
isElabTask :: DeclToken -> Bool
|
2020-01-31 04:17:17 +01:00
|
|
|
isElabTask (DTIdent _ x) = elem x elabTasks
|
2019-09-18 02:30:17 +02:00
|
|
|
where elabTasks = ["$fatal", "$error", "$warning", "$info"]
|
|
|
|
|
isElabTask _ = False
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2019-09-18 02:30:17 +02:00
|
|
|
-- internal; approximates the behavior of the elaboration system tasks
|
|
|
|
|
asElabTask :: [DeclToken] -> [ModuleItem]
|
2021-07-03 19:23:33 +02:00
|
|
|
asElabTask [DTIdent _ name, DTPorts _ args] =
|
2019-09-18 02:30:17 +02:00
|
|
|
if name == "$info"
|
|
|
|
|
then [] -- just drop them for simplicity
|
2020-06-18 04:01:59 +02:00
|
|
|
else [Instance "ThisModuleDoesNotExist" [] name' [] args]
|
2019-09-18 02:30:17 +02:00
|
|
|
where name' = "__sv2v_elab_" ++ tail name
|
2020-01-31 04:17:17 +01:00
|
|
|
asElabTask [DTIdent pos name] =
|
2021-07-03 19:23:33 +02:00
|
|
|
asElabTask [DTIdent pos name, DTPorts pos []]
|
2019-09-18 02:30:17 +02:00
|
|
|
asElabTask tokens =
|
|
|
|
|
error $ "could not parse elaboration system task: " ++ show tokens
|
|
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
-- internal; parser for module instantiations
|
|
|
|
|
parseDTsAsIntantiations :: [DeclToken] -> [ModuleItem]
|
2021-07-03 19:23:33 +02:00
|
|
|
parseDTsAsIntantiations (DTIdent _ name : DTParams _ params : tokens) =
|
|
|
|
|
step tokens
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
2019-03-25 23:53:55 +01:00
|
|
|
step :: [DeclToken] -> [ModuleItem]
|
2021-07-03 19:23:33 +02:00
|
|
|
step [] = parseError endTok "unexpected end of instantiation list"
|
|
|
|
|
step toks = inst : rest
|
2019-03-25 23:53:55 +01:00
|
|
|
where
|
2021-07-03 19:23:33 +02:00
|
|
|
(delimTok, rest) =
|
|
|
|
|
if null restToks
|
|
|
|
|
then (endTok, [])
|
|
|
|
|
else (head restToks, step $ tail restToks)
|
|
|
|
|
inst = Instance name params x rs p
|
|
|
|
|
(x, rs, p) = parseDTsAsIntantiation instToks delimTok
|
|
|
|
|
(instToks, restToks) = break isComma toks
|
|
|
|
|
-- TODO: all public interfaces should take the ending token
|
|
|
|
|
endTok = last tokens
|
|
|
|
|
parseDTsAsIntantiations (DTIdent pos name : tokens) =
|
|
|
|
|
parseDTsAsIntantiations $ DTIdent pos name : DTParams pos [] : tokens
|
2019-03-04 08:58:00 +01:00
|
|
|
parseDTsAsIntantiations tokens =
|
2021-07-03 19:23:33 +02:00
|
|
|
parseError (head tokens)
|
|
|
|
|
"expected module or interface name at beginning of instantiation list"
|
|
|
|
|
|
|
|
|
|
-- internal; parser for an individual instantiations
|
|
|
|
|
parseDTsAsIntantiation :: [DeclToken] -> DeclToken
|
|
|
|
|
-> (Identifier, [Range], [PortBinding])
|
|
|
|
|
parseDTsAsIntantiation l0 delimTok =
|
|
|
|
|
if null l0 then
|
|
|
|
|
parseError delimTok "expected instantiation before delimiter"
|
|
|
|
|
else if not (isIdent nameTok) then
|
|
|
|
|
parseError nameTok "expected instantiation name"
|
|
|
|
|
else if null l1 then
|
|
|
|
|
parseError delimTok "expected port connections before delimiter"
|
|
|
|
|
else if seq ranges not (isPorts portsTok) then
|
|
|
|
|
parseError portsTok "expected port connections"
|
|
|
|
|
else
|
|
|
|
|
(name, ranges, ports)
|
|
|
|
|
where
|
|
|
|
|
Just (nameTok, l1) = uncons l0
|
|
|
|
|
rangeToks = init l1
|
|
|
|
|
portsTok = last l1
|
|
|
|
|
DTIdent _ name = nameTok
|
|
|
|
|
DTPorts _ ports = portsTok
|
|
|
|
|
ranges = map asRange rangeToks
|
|
|
|
|
asRange :: DeclToken -> Range
|
|
|
|
|
asRange (DTRange _ (NonIndexed, s)) = s
|
|
|
|
|
asRange (DTBit _ s) = (RawNum 0, BinOp Sub s (RawNum 1))
|
|
|
|
|
asRange tok = parseError tok "expected instantiation dimensions"
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
-- [PUBLIC]: parser for generic, comma-separated declarations
|
|
|
|
|
parseDTsAsDecls :: [DeclToken] -> [Decl]
|
|
|
|
|
parseDTsAsDecls tokens =
|
2021-07-03 19:23:33 +02:00
|
|
|
forbidNonEqAsgn tokens `seq`
|
2019-03-04 08:58:00 +01:00
|
|
|
concat $ map finalize $ parseDTsAsComponents tokens
|
|
|
|
|
|
|
|
|
|
|
2021-07-03 19:23:33 +02:00
|
|
|
-- internal; used for "single" declarations, i.e., declarations appearing
|
2019-03-04 08:58:00 +01:00
|
|
|
-- outside of a port list
|
|
|
|
|
parseDTsAsDecl :: [DeclToken] -> [Decl]
|
|
|
|
|
parseDTsAsDecl tokens =
|
|
|
|
|
if length components /= 1
|
2021-07-03 19:23:33 +02:00
|
|
|
then parseError tok $ "unexpected comma-separated declarations"
|
2019-03-04 08:58:00 +01:00
|
|
|
else finalize $ head components
|
2021-07-03 19:23:33 +02:00
|
|
|
where
|
|
|
|
|
components = parseDTsAsComponents tokens
|
|
|
|
|
_ : (pos, _, _) : _ = components
|
|
|
|
|
tok = DTComma pos
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
|
2019-03-05 02:58:09 +01:00
|
|
|
-- [PUBLIC]: parser for single block item declarations or assign or arg-less
|
2020-01-31 04:17:17 +01:00
|
|
|
-- subroutine call statements
|
|
|
|
|
parseDTsAsDeclOrStmt :: [DeclToken] -> ([Decl], [Stmt])
|
2020-02-01 21:52:52 +01:00
|
|
|
parseDTsAsDeclOrStmt (DTAsgn pos (AsgnOp op) mt e : tok : toks) =
|
|
|
|
|
parseDTsAsDeclOrStmt $ (tok : toks) ++ [DTAsgn pos (AsgnOp op) mt e]
|
2020-01-31 04:17:17 +01:00
|
|
|
parseDTsAsDeclOrStmt tokens =
|
2020-12-01 04:34:14 +01:00
|
|
|
if not hasLeadingDecl
|
2020-01-31 04:17:17 +01:00
|
|
|
then ([], [traceStmt pos, stmt])
|
2019-03-04 20:25:38 +01:00
|
|
|
else (parseDTsAsDecl tokens, [])
|
|
|
|
|
where
|
2020-01-31 04:17:17 +01:00
|
|
|
pos = tokPos $ last tokens
|
2019-10-19 22:22:39 +02:00
|
|
|
stmt = case last tokens of
|
2020-02-01 21:52:52 +01:00
|
|
|
DTAsgn _ op mt e -> Asgn op mt lhs e
|
2021-07-03 19:23:33 +02:00
|
|
|
DTPorts _ ports -> asSubroutine lhsToks (portsToArgs ports)
|
2021-05-30 04:23:20 +02:00
|
|
|
_ -> asSubroutine tokens (Args [] [])
|
2021-04-08 06:42:18 +02:00
|
|
|
lhsToks = init tokens
|
|
|
|
|
lhs = case takeLHS lhsToks of
|
|
|
|
|
Nothing -> error $ "could not parse as LHS: " ++ show lhsToks
|
|
|
|
|
Just l -> l
|
2021-07-02 23:59:21 +02:00
|
|
|
hasLeadingDecl = tokens /= l5 && tripLookahead l5
|
2020-12-01 04:34:14 +01:00
|
|
|
(_, l1) = takeDir tokens
|
|
|
|
|
(_, l2) = takeLifetime l1
|
2021-07-02 23:59:21 +02:00
|
|
|
(_, l3) = takeVarOrNet l2
|
|
|
|
|
(_, l4) = takeType l3
|
|
|
|
|
(_, l5) = takeRanges l4
|
2019-10-19 22:22:39 +02:00
|
|
|
|
2020-01-31 04:17:17 +01:00
|
|
|
traceStmt :: Position -> Stmt
|
|
|
|
|
traceStmt pos = CommentStmt $ "Trace: " ++ show pos
|
|
|
|
|
|
2021-05-30 04:23:20 +02:00
|
|
|
-- read the given tokens as the root of a subroutine invocation
|
|
|
|
|
asSubroutine :: [DeclToken] -> Args -> Stmt
|
|
|
|
|
asSubroutine [DTIdent _ x] = Subroutine $ Ident x
|
|
|
|
|
asSubroutine [DTPSIdent _ p x] = Subroutine $ PSIdent p x
|
|
|
|
|
asSubroutine [DTCSIdent _ c p x] = Subroutine $ CSIdent c p x
|
|
|
|
|
asSubroutine tokens =
|
|
|
|
|
case takeLHS tokens of
|
|
|
|
|
Just lhs -> Subroutine $ lhsToExpr lhs
|
|
|
|
|
Nothing -> error $ "invalid block item decl or stmt: " ++ show tokens
|
|
|
|
|
|
2019-10-19 22:22:39 +02:00
|
|
|
-- converts port bindings to call args
|
2021-07-03 19:23:33 +02:00
|
|
|
portsToArgs :: [PortBinding] -> Args
|
|
|
|
|
portsToArgs bindings =
|
2019-10-19 22:22:39 +02:00
|
|
|
Args pnArgs kwArgs
|
|
|
|
|
where
|
|
|
|
|
(pnBindings, kwBindings) = partition (null . fst) bindings
|
|
|
|
|
pnArgs = map snd pnBindings
|
|
|
|
|
kwArgs = kwBindings
|
2019-03-27 06:53:26 +01:00
|
|
|
|
2019-10-01 05:03:55 +02:00
|
|
|
-- [PUBLIC]: parser for comma-separated declarations or assignment lists; this
|
|
|
|
|
-- is only used for `for` loop initialization lists
|
|
|
|
|
parseDTsAsDeclsOrAsgns :: [DeclToken] -> Either [Decl] [(LHS, Expr)]
|
|
|
|
|
parseDTsAsDeclsOrAsgns tokens =
|
2021-07-03 19:23:33 +02:00
|
|
|
forbidNonEqAsgn tokens `seq`
|
2019-03-27 08:33:28 +01:00
|
|
|
if hasLeadingAsgn || tripLookahead tokens
|
2019-10-01 05:03:55 +02:00
|
|
|
then Right $ parseDTsAsAsgns tokens
|
2021-03-06 01:58:44 +01:00
|
|
|
else Left $ map checkDecl $ parseDTsAsDecls tokens
|
2019-03-27 06:53:26 +01:00
|
|
|
where
|
|
|
|
|
hasLeadingAsgn =
|
|
|
|
|
-- if there is an asgn token before the next comma
|
2020-01-31 04:17:17 +01:00
|
|
|
case (findIndex isComma tokens, findIndex isAsgnToken tokens) of
|
2019-03-27 06:53:26 +01:00
|
|
|
(Just a, Just b) -> a > b
|
|
|
|
|
(Nothing, Just _) -> True
|
|
|
|
|
_ -> False
|
2021-03-06 01:58:44 +01:00
|
|
|
checkDecl :: Decl -> Decl
|
|
|
|
|
checkDecl (decl @ (Variable _ _ _ _ Nil)) =
|
|
|
|
|
error $ "for loop declaration missing initialization: "
|
|
|
|
|
++ init (show decl)
|
|
|
|
|
checkDecl decl = decl
|
2019-10-01 05:03:55 +02:00
|
|
|
|
|
|
|
|
-- internal parser for basic assignment lists
|
|
|
|
|
parseDTsAsAsgns :: [DeclToken] -> [(LHS, Expr)]
|
|
|
|
|
parseDTsAsAsgns tokens =
|
|
|
|
|
case l1 of
|
|
|
|
|
[] -> [asgn]
|
2020-01-31 04:17:17 +01:00
|
|
|
DTComma{} : remaining -> asgn : parseDTsAsAsgns remaining
|
2019-10-01 05:03:55 +02:00
|
|
|
_ -> error $ "bad assignment tokens: " ++ show tokens
|
|
|
|
|
where
|
|
|
|
|
(lhsToks, l0) = break isDTAsgn tokens
|
|
|
|
|
lhs = case takeLHS lhsToks of
|
|
|
|
|
Nothing -> error $ "could not parse as LHS: " ++ show lhsToks
|
|
|
|
|
Just l -> l
|
2020-02-01 21:52:52 +01:00
|
|
|
DTAsgn _ AsgnOpEq Nothing expr : l1 = l0
|
2019-10-01 05:03:55 +02:00
|
|
|
asgn = (lhs, expr)
|
|
|
|
|
|
2019-03-27 08:33:28 +01:00
|
|
|
isDTAsgn :: DeclToken -> Bool
|
2020-02-01 21:52:52 +01:00
|
|
|
isDTAsgn (DTAsgn _ _ Nothing _) = True
|
2019-03-27 08:33:28 +01:00
|
|
|
isDTAsgn _ = False
|
2019-03-27 06:53:26 +01:00
|
|
|
|
|
|
|
|
isAsgnToken :: DeclToken -> Bool
|
2020-02-01 21:52:52 +01:00
|
|
|
isAsgnToken (DTBit{} ) = True
|
|
|
|
|
isAsgnToken (DTConcat{}) = True
|
|
|
|
|
isAsgnToken (DTStream{}) = True
|
|
|
|
|
isAsgnToken (DTDot{} ) = True
|
|
|
|
|
isAsgnToken (DTAsgn _ op _ _) = op /= AsgnOpEq
|
2019-03-27 06:53:26 +01:00
|
|
|
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
|
2020-01-31 04:17:17 +01: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
|
2020-01-31 04:17:17 +01:00
|
|
|
takeLHSStep (Just curr) (DTBit _ e ) = Just $ LHSBit curr e
|
|
|
|
|
takeLHSStep (Just curr) (DTRange _ (m,r)) = Just $ LHSRange curr m r
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
2020-01-31 04:17:17 +01:00
|
|
|
-- batches together separate declaration lists
|
2021-07-03 19:23:33 +02:00
|
|
|
type DeclBase = Identifier -> [Range] -> Expr -> Decl
|
2020-06-14 21:56:09 +02:00
|
|
|
type Triplet = (Identifier, [Range], Expr)
|
2021-07-03 19:23:33 +02:00
|
|
|
type Component = (Position, DeclBase, [Triplet])
|
|
|
|
|
finalize :: Component -> [Decl]
|
|
|
|
|
finalize (pos, base, trips) =
|
2020-01-31 04:17:17 +01:00
|
|
|
CommentDecl ("Trace: " ++ show pos) :
|
2021-07-03 19:23:33 +02:00
|
|
|
map (\(x, a, e) -> base x a e) trips
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
-- internal; entrypoint of the critical portion of our parser
|
2021-07-03 19:23:33 +02:00
|
|
|
parseDTsAsComponents :: [DeclToken] -> [Component]
|
2019-03-04 08:58:00 +01:00
|
|
|
parseDTsAsComponents [] = []
|
2019-03-27 06:53:26 +01:00
|
|
|
parseDTsAsComponents tokens =
|
2021-07-03 19:23:33 +02:00
|
|
|
component : parseDTsAsComponents tokens'
|
|
|
|
|
where (component, tokens') = parseDTsAsComponent tokens
|
2019-03-27 06:53:26 +01:00
|
|
|
|
2021-07-03 19:23:33 +02:00
|
|
|
parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken])
|
2019-03-27 06:53:26 +01:00
|
|
|
parseDTsAsComponent [] = error "parseDTsAsComponent unexpected end of tokens"
|
|
|
|
|
parseDTsAsComponent l0 =
|
2020-07-23 05:35:25 +02:00
|
|
|
if l /= Nothing && l /= Just Automatic then
|
|
|
|
|
error $ "unexpected non-automatic lifetime: " ++ show l0
|
2021-07-02 23:59:21 +02:00
|
|
|
else if dir == Local && length l2 == length l5 then
|
2020-07-23 05:35:25 +02:00
|
|
|
error $ "declaration(s) missing type information: "
|
|
|
|
|
++ show (position, tps)
|
|
|
|
|
else
|
2021-07-03 19:23:33 +02:00
|
|
|
(component, l6)
|
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
|
2021-07-02 23:59:21 +02:00
|
|
|
(von, l3) = takeVarOrNet l2
|
|
|
|
|
(tf , l4) = takeType l3
|
|
|
|
|
(rs , l5) = takeRanges l4
|
|
|
|
|
(tps, l6) = takeTrips l5 True
|
2020-01-31 04:17:17 +01:00
|
|
|
position = tokPos $ head l0
|
2021-07-03 19:23:33 +02:00
|
|
|
base = von dir $ tf rs
|
|
|
|
|
component = (position, base, tps)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
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
|
2020-06-14 21:56:09 +02:00
|
|
|
(x, l1) = takeIdent l0
|
|
|
|
|
(a, l2) = takeRanges l1
|
|
|
|
|
(e, l3) = takeAsgn l2
|
|
|
|
|
(_, l4) = takeComma l3
|
|
|
|
|
trip = (x, a, e)
|
2019-03-04 08:58:00 +01:00
|
|
|
(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
|
2020-06-14 21:56:09 +02:00
|
|
|
else if null l1 || asgn /= Nil then
|
2019-03-04 08:58:00 +01:00
|
|
|
True
|
2019-09-11 18:54:51 +02:00
|
|
|
-- if there is an ident followed by some number of ranges, and that's it,
|
|
|
|
|
-- then there is a trailing declaration of an array ahead
|
|
|
|
|
else if (not $ null l1) && (null l2) then
|
|
|
|
|
True
|
2019-03-04 08:58:00 +01:00
|
|
|
-- 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
|
2020-01-31 04:17:17 +01:00
|
|
|
(not $ null l3) && (isComma $ head l3)
|
2019-03-04 08:58:00 +01:00
|
|
|
where
|
|
|
|
|
(_ , l1) = takeIdent l0
|
|
|
|
|
(_ , l2) = takeRanges l1
|
|
|
|
|
(asgn, l3) = takeAsgn l2
|
|
|
|
|
|
|
|
|
|
takeDir :: [DeclToken] -> (Direction, [DeclToken])
|
2020-01-31 04:17:17 +01:00
|
|
|
takeDir (DTDir _ dir : rest) = (dir , rest)
|
|
|
|
|
takeDir rest = (Local, rest)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2019-08-31 21:32:24 +02:00
|
|
|
takeLifetime :: [DeclToken] -> (Maybe Lifetime, [DeclToken])
|
2020-01-31 04:17:17 +01:00
|
|
|
takeLifetime (DTLifetime _ l : rest) = (Just l, rest)
|
|
|
|
|
takeLifetime rest = (Nothing, rest)
|
2019-08-31 21:32:24 +02:00
|
|
|
|
2021-07-03 19:23:33 +02:00
|
|
|
takeVarOrNet :: [DeclToken] -> (Direction -> Type -> DeclBase, [DeclToken])
|
|
|
|
|
takeVarOrNet (DTConst{} : tok @ DTConst{} : _) =
|
|
|
|
|
parseError tok "duplicate const modifier"
|
2021-07-02 23:59:21 +02:00
|
|
|
takeVarOrNet (DTConst _ : tokens) = takeVarOrNet tokens
|
2021-07-03 19:23:33 +02:00
|
|
|
takeVarOrNet (DTNet _ n s : tokens) = (\d -> Net d n s, tokens)
|
|
|
|
|
takeVarOrNet tokens = (Variable, tokens)
|
2021-07-02 23:59:21 +02:00
|
|
|
|
2019-03-04 08:58:00 +01:00
|
|
|
takeType :: [DeclToken] -> ([Range] -> Type, [DeclToken])
|
2021-04-13 16:45:26 +02:00
|
|
|
takeType (DTIdent _ a : DTDot _ b : rest) = (InterfaceT a b , rest)
|
2020-01-31 04:17:17 +01:00
|
|
|
takeType (DTType _ tf : DTSigning _ sg : rest) = (tf sg , rest)
|
|
|
|
|
takeType (DTType _ tf : rest) = (tf Unspecified , rest)
|
|
|
|
|
takeType (DTSigning _ sg : rest) = (Implicit sg , rest)
|
2020-07-10 05:01:18 +02:00
|
|
|
takeType (DTPSIdent _ ps tn : rest) = (PSAlias ps tn , rest)
|
|
|
|
|
takeType (DTCSIdent _ ps pm tn : rest) = (CSAlias ps pm tn , rest)
|
2020-01-31 04:17:17 +01:00
|
|
|
takeType (DTIdent pos tn : rest) =
|
2019-09-26 01:34:42 +02:00
|
|
|
if couldBeTypename
|
2020-07-09 01:46:37 +02:00
|
|
|
then (Alias tn , rest)
|
2020-01-31 04:17:17 +01:00
|
|
|
else (Implicit Unspecified, DTIdent pos tn : rest)
|
2019-09-26 01:34:42 +02:00
|
|
|
where
|
|
|
|
|
couldBeTypename =
|
2020-01-31 04:17:17 +01:00
|
|
|
case (findIndex isIdent rest, findIndex isComma rest) of
|
2019-09-26 01:34:42 +02:00
|
|
|
-- no identifiers left => no decl asgns
|
|
|
|
|
(Nothing, _) -> False
|
|
|
|
|
-- an identifier is left, and no more commas
|
|
|
|
|
(_, Nothing) -> True
|
|
|
|
|
-- if comma is first, then this ident is a declaration
|
|
|
|
|
(Just a, Just b) -> a < b
|
2021-07-03 19:23:33 +02:00
|
|
|
takeType (DTVar{} : tok @ DTVar{} : _) =
|
|
|
|
|
parseError tok "duplicate var modifier"
|
2021-07-02 23:59:21 +02:00
|
|
|
takeType (DTVar _ : rest) =
|
|
|
|
|
case tf [] of
|
|
|
|
|
Implicit sg [] -> (IntegerVector TLogic sg, rest')
|
|
|
|
|
_ -> (tf, rest')
|
|
|
|
|
where (tf, rest') = takeType rest
|
2019-09-26 01:34:42 +02: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
|
2020-01-31 04:17:17 +01:00
|
|
|
DTRange _ (NonIndexed, r) -> (r : rs, rest )
|
|
|
|
|
DTBit _ s -> (asRange s : rs, rest )
|
|
|
|
|
DTAutoDim _ ->
|
2019-09-28 22:57:36 +02:00
|
|
|
case rest of
|
2020-02-01 21:52:52 +01:00
|
|
|
(DTAsgn _ AsgnOpEq Nothing (Pattern l) : _) -> autoDim l
|
|
|
|
|
(DTAsgn _ AsgnOpEq Nothing (Concat l) : _) -> autoDim l
|
2020-01-31 04:17:17 +01:00
|
|
|
_ -> ([] , token : tokens)
|
|
|
|
|
_ -> ([] , token : tokens)
|
2019-03-07 07:38:42 +01:00
|
|
|
where
|
|
|
|
|
(rs, rest) = takeRanges tokens
|
2020-07-12 23:06:27 +02:00
|
|
|
asRange s = (RawNum 0, BinOp Sub s (RawNum 1))
|
2019-09-28 22:57:36 +02:00
|
|
|
autoDim :: [a] -> ([Range], [DeclToken])
|
|
|
|
|
autoDim l =
|
|
|
|
|
((lo, hi) : rs, rest)
|
|
|
|
|
where
|
|
|
|
|
n = length l
|
2020-07-12 23:06:27 +02:00
|
|
|
lo = RawNum 0
|
|
|
|
|
hi = RawNum $ fromIntegral $ n - 1
|
2019-03-04 08:58:00 +01:00
|
|
|
|
2020-02-01 21:52:52 +01:00
|
|
|
-- Matching `AsgnOpEq` and `AsgnOpNonBlocking` here allows tripLookahead to work
|
|
|
|
|
-- both for standard declarations and in `parseDTsAsDeclOrStmt`, where we're
|
|
|
|
|
-- checking for an assignment statement. The other entry points disallow
|
|
|
|
|
-- `AsgnOpNonBlocking`, so this doesn't liberalize the parser.
|
2020-06-14 21:56:09 +02:00
|
|
|
takeAsgn :: [DeclToken] -> (Expr, [DeclToken])
|
2020-02-01 21:52:52 +01:00
|
|
|
takeAsgn (DTAsgn _ op Nothing e : rest) =
|
|
|
|
|
if op == AsgnOpEq || op == AsgnOpNonBlocking
|
2020-06-14 21:56:09 +02:00
|
|
|
then (e , rest)
|
|
|
|
|
else (Nil, rest)
|
|
|
|
|
takeAsgn rest = (Nil, rest)
|
2019-03-04 08:58:00 +01:00
|
|
|
|
|
|
|
|
takeComma :: [DeclToken] -> (Bool, [DeclToken])
|
|
|
|
|
takeComma [] = (False, [])
|
2020-01-31 04:17:17 +01:00
|
|
|
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])
|
2020-01-31 04:17:17 +01:00
|
|
|
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
|
2020-01-31 04:17:17 +01:00
|
|
|
isIdent (DTIdent{}) = True
|
2019-03-04 08:58:00 +01:00
|
|
|
isIdent _ = False
|
2020-01-31 04:17:17 +01:00
|
|
|
|
|
|
|
|
isComma :: DeclToken -> Bool
|
|
|
|
|
isComma (DTComma{}) = True
|
|
|
|
|
isComma _ = False
|
|
|
|
|
|
2021-07-03 19:23:33 +02:00
|
|
|
isPorts :: DeclToken -> Bool
|
|
|
|
|
isPorts DTPorts{} = True
|
|
|
|
|
isPorts _ = False
|
|
|
|
|
|
2020-01-31 04:17:17 +01:00
|
|
|
tokPos :: DeclToken -> Position
|
|
|
|
|
tokPos (DTComma p) = p
|
|
|
|
|
tokPos (DTAutoDim p) = p
|
2021-07-02 23:59:21 +02:00
|
|
|
tokPos (DTConst p) = p
|
|
|
|
|
tokPos (DTVar p) = p
|
2020-02-01 21:52:52 +01:00
|
|
|
tokPos (DTAsgn p _ _ _) = p
|
2020-01-31 04:17:17 +01:00
|
|
|
tokPos (DTRange p _) = p
|
2020-07-10 05:01:18 +02:00
|
|
|
tokPos (DTIdent p _) = p
|
|
|
|
|
tokPos (DTPSIdent p _ _) = p
|
2020-07-09 01:46:37 +02:00
|
|
|
tokPos (DTCSIdent p _ _ _) = p
|
2020-01-31 04:17:17 +01:00
|
|
|
tokPos (DTDir p _) = p
|
|
|
|
|
tokPos (DTType p _) = p
|
2021-07-02 23:59:21 +02:00
|
|
|
tokPos (DTNet p _ _) = p
|
2020-01-31 04:17:17 +01:00
|
|
|
tokPos (DTParams p _) = p
|
2021-07-03 19:23:33 +02:00
|
|
|
tokPos (DTPorts p _) = p
|
2020-01-31 04:17:17 +01:00
|
|
|
tokPos (DTBit p _) = p
|
|
|
|
|
tokPos (DTConcat p _) = p
|
|
|
|
|
tokPos (DTStream p _ _ _) = p
|
|
|
|
|
tokPos (DTDot p _) = p
|
|
|
|
|
tokPos (DTSigning p _) = p
|
|
|
|
|
tokPos (DTLifetime p _) = p
|
2020-12-08 19:28:28 +01:00
|
|
|
tokPos (DTAttr p _) = p
|
2021-07-03 19:23:33 +02:00
|
|
|
|
|
|
|
|
parseError :: DeclToken -> String -> a
|
|
|
|
|
parseError tok msg = error $ show pos ++ ": Parse error: " ++ msg
|
|
|
|
|
where pos = tokPos tok
|