Commit 5fd21ebf by Zachary Snow

improved parsing in declaration contexts

- support for additional assignment statements in loop initializations
- greatly improved error messaging in these contexts
- decl parser takes in the ending token; significant related refactoring
- pass through elaboration system tasks
- removed non-blocking assignment operator precedence hack
- preliminary nosim test suite for features unsupported by iverilog
parent 6ee558b6
...@@ -625,6 +625,11 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper = ...@@ -625,6 +625,11 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper =
a' <- traverseAssertionStmtsM stmtMapper a a' <- traverseAssertionStmtsM stmtMapper a
a'' <- traverseAssertionExprsM exprMapper a' a'' <- traverseAssertionExprsM exprMapper a'
return $ AssertionItem (mx, a'') return $ AssertionItem (mx, a'')
moduleItemMapper (ElabTask severity (Args pnArgs kwArgs)) = do
pnArgs' <- mapM exprMapper pnArgs
kwArgs' <- fmap (zip kwNames) $ mapM exprMapper kwExprs
return $ ElabTask severity $ Args pnArgs' kwArgs'
where (kwNames, kwExprs) = unzip kwArgs
genItemMapper = traverseGenItemExprsM exprMapper genItemMapper = traverseGenItemExprsM exprMapper
......
...@@ -14,6 +14,7 @@ module Language.SystemVerilog.AST.ModuleItem ...@@ -14,6 +14,7 @@ module Language.SystemVerilog.AST.ModuleItem
, NInputGateKW (..) , NInputGateKW (..)
, NOutputGateKW (..) , NOutputGateKW (..)
, AssignOption (..) , AssignOption (..)
, Severity (..)
) where ) where
import Data.List (intercalate) import Data.List (intercalate)
...@@ -24,7 +25,7 @@ import Language.SystemVerilog.AST.ShowHelp ...@@ -24,7 +25,7 @@ import Language.SystemVerilog.AST.ShowHelp
import Language.SystemVerilog.AST.Attr (Attr) import Language.SystemVerilog.AST.Attr (Attr)
import Language.SystemVerilog.AST.Decl (Direction) import Language.SystemVerilog.AST.Decl (Direction)
import Language.SystemVerilog.AST.Description (PackageItem) import Language.SystemVerilog.AST.Description (PackageItem)
import Language.SystemVerilog.AST.Expr (Expr(Nil), pattern Ident, Range, showRanges, ParamBinding, showParams) import Language.SystemVerilog.AST.Expr (Expr(Nil), pattern Ident, Range, showRanges, ParamBinding, showParams, Args)
import Language.SystemVerilog.AST.GenItem (GenItem) import Language.SystemVerilog.AST.GenItem (GenItem)
import Language.SystemVerilog.AST.LHS (LHS) import Language.SystemVerilog.AST.LHS (LHS)
import Language.SystemVerilog.AST.Stmt (Stmt, AssertionItem, Timing(Delay)) import Language.SystemVerilog.AST.Stmt (Stmt, AssertionItem, Timing(Delay))
...@@ -41,6 +42,7 @@ data ModuleItem ...@@ -41,6 +42,7 @@ data ModuleItem
| Modport Identifier [ModportDecl] | Modport Identifier [ModportDecl]
| Initial Stmt | Initial Stmt
| Final Stmt | Final Stmt
| ElabTask Severity Args
| MIPackageItem PackageItem | MIPackageItem PackageItem
| NInputGate NInputGateKW Expr Identifier LHS [Expr] | NInputGate NInputGateKW Expr Identifier LHS [Expr]
| NOutputGate NOutputGateKW Expr Identifier [LHS] Expr | NOutputGate NOutputGateKW Expr Identifier [LHS] Expr
...@@ -58,6 +60,7 @@ instance Show ModuleItem where ...@@ -58,6 +60,7 @@ instance Show ModuleItem where
show (Modport x l) = printf "modport %s(\n%s\n);" x (indent $ intercalate ",\n" $ map showModportDecl l) show (Modport x l) = printf "modport %s(\n%s\n);" x (indent $ intercalate ",\n" $ map showModportDecl l)
show (Initial s ) = printf "initial %s" (show s) show (Initial s ) = printf "initial %s" (show s)
show (Final s ) = printf "final %s" (show s) show (Final s ) = printf "final %s" (show s)
show (ElabTask s a) = printf "%s%s;" (show s) (show a)
show (NInputGate kw d x lhs exprs) = show (NInputGate kw d x lhs exprs) =
showGate kw d x $ show lhs : map show exprs showGate kw d x $ show lhs : map show exprs
show (NOutputGate kw d x lhss expr) = show (NOutputGate kw d x lhss expr) =
...@@ -148,3 +151,16 @@ instance Show AssignOption where ...@@ -148,3 +151,16 @@ instance Show AssignOption where
show AssignOptionNone = "" show AssignOptionNone = ""
show (AssignOptionDelay de) = printf "#(%s)" (show de) show (AssignOptionDelay de) = printf "#(%s)" (show de)
show (AssignOptionDrive s0 s1) = printf "(%s, %s)" (show s0) (show s1) show (AssignOptionDrive s0 s1) = printf "(%s, %s)" (show s0) (show s1)
data Severity
= SeverityInfo
| SeverityWarning
| SeverityError
| SeverityFatal
deriving Eq
instance Show Severity where
show SeverityInfo = "$info"
show SeverityWarning = "$warning"
show SeverityError = "$error"
show SeverityFatal = "$fatal"
...@@ -401,7 +401,6 @@ time { Token Lit_time _ _ } ...@@ -401,7 +401,6 @@ time { Token Lit_time _ _ }
-- operator precedences, from *lowest* to *highest* -- operator precedences, from *lowest* to *highest*
%nonassoc DefaultStrength %nonassoc DefaultStrength
%nonassoc DriveStrength ChargeStrength %nonassoc DriveStrength ChargeStrength
%nonassoc Asgn
%nonassoc NoElse %nonassoc NoElse
%nonassoc "else" %nonassoc "else"
%right "|->" "|=>" "#-#" "#=#" %right "|->" "|=>" "#-#" "#=#"
...@@ -630,17 +629,17 @@ Strength :: { Strength } ...@@ -630,17 +629,17 @@ Strength :: { Strength }
DeclTokens(delim) :: { [DeclToken] } DeclTokens(delim) :: { [DeclToken] }
: DeclTokensBase(DeclTokens(delim), delim) { $1 } : DeclTokensBase(DeclTokens(delim), delim) { $1 }
DeclTokensBase(repeat, delim) :: { [DeclToken] } DeclTokensBase(repeat, delim) :: { [DeclToken] }
: DeclToken delim { [$1] } : DeclToken DTDelim(delim) { [$1, $2] }
| DeclToken repeat { [$1] ++ $2 } | DeclToken repeat { [$1] ++ $2 }
| IdentifierP ParamBindings repeat { [uncurry DTIdent $1, DTParams (fst $1) $2] ++ $3 } | IdentifierP ParamBindings repeat { [uncurry DTIdent $1, DTParams (fst $1) $2] ++ $3 }
| DeclTokenAsgn "," repeat { [$1, DTComma (tokenPosition $2)] ++ $3 } | DeclTokenAsgn "," repeat { [$1, DTComma (tokenPosition $2)] ++ $3 }
| DeclTokenAsgn delim { [$1] } | DeclTokenAsgn DTDelim(delim) { [$1, $2] }
DeclToken :: { DeclToken } DeclToken :: { DeclToken }
: "," { DTComma $ tokenPosition $1 } : "," { DTComma $ tokenPosition $1 }
| "[" "]" { DTAutoDim $ tokenPosition $1 } | "[" "]" { DTAutoDim $ tokenPosition $1 }
| "const" { DTConst $ tokenPosition $1 } | "const" { DTConst $ tokenPosition $1 }
| "var" { DTVar $ tokenPosition $1 } | "var" { DTVar $ tokenPosition $1 }
| PartSelectP { uncurry DTRange $1 } | PartSelectP { uncurry (DTRange $ fst $1) (snd $1) }
| IdentifierP { uncurry DTIdent $1 } | IdentifierP { uncurry DTIdent $1 }
| DirectionP { uncurry DTDir $1 } | DirectionP { uncurry DTDir $1 }
| LHSConcatP { uncurry DTConcat $1 } | LHSConcatP { uncurry DTConcat $1 }
...@@ -655,21 +654,23 @@ DeclToken :: { DeclToken } ...@@ -655,21 +654,23 @@ DeclToken :: { DeclToken }
| "{" StreamOp Concat "}" { DTStream (tokenPosition $1) $2 (RawNum 1) (map toLHS $3) } | "{" StreamOp Concat "}" { DTStream (tokenPosition $1) $2 (RawNum 1) (map toLHS $3) }
| "type" "(" Expr ")" { uncurry DTType $ makeTypeOf $1 $3 } | "type" "(" Expr ")" { uncurry DTType $ makeTypeOf $1 $3 }
| IncOrDecOperatorP { DTAsgn (fst $1) (AsgnOp $ snd $1) Nothing (RawNum 1) } | IncOrDecOperatorP { DTAsgn (fst $1) (AsgnOp $ snd $1) Nothing (RawNum 1) }
| "<=" opt(DelayOrEvent) Expr %prec Asgn { DTAsgn (tokenPosition $1) AsgnOpNonBlocking $2 $3 }
| IdentifierP "::" Identifier { uncurry DTPSIdent $1 $3 } | IdentifierP "::" Identifier { uncurry DTPSIdent $1 $3 }
| IdentifierP ParamBindings "::" Identifier { uncurry DTCSIdent $1 $2 $4 } | IdentifierP ParamBindings "::" Identifier { uncurry DTCSIdent $1 $2 $4 }
DTDelim(delim) :: { DeclToken }
: delim { DTEnd (tokenPosition $1) (head $ tokenString $1) }
DeclTokenAsgn :: { DeclToken } DeclTokenAsgn :: { DeclToken }
: "=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpEq $2 $3 } : "=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpEq $2 $3 }
| AsgnBinOpP Expr { uncurry DTAsgn $1 Nothing $2 } | AsgnBinOpP Expr { uncurry DTAsgn $1 Nothing $2 }
| "<=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpNonBlocking $2 $3 }
PortDeclTokens(delim) :: { [DeclToken] } PortDeclTokens(delim) :: { [DeclToken] }
: DeclTokensBase(PortDeclTokens(delim), delim) { $1 } : DeclTokensBase(PortDeclTokens(delim), delim) { $1 }
| GenericInterfaceDecl PortDeclTokens(delim) { $1 ++ $2} | GenericInterfaceDecl PortDeclTokens(delim) { $1 ++ $2}
| GenericInterfaceDecl delim { $1 } | GenericInterfaceDecl DTDelim(delim) { $1 ++ [$2] }
| AttributeInstanceP PortDeclTokens(delim) { uncurry DTAttr $1 : $2 } | AttributeInstanceP PortDeclTokens(delim) { uncurry DTAttr $1 : $2 }
ModuleDeclTokens(delim) :: { [DeclToken] } ModuleDeclTokens(delim) :: { [DeclToken] }
: DeclTokensBase(ModuleDeclTokens(delim), delim) { $1 } : DeclTokensBase(ModuleDeclTokens(delim), delim) { $1 }
| GenericInterfaceDecl ModuleDeclTokens(delim) { $1 ++ $2} | GenericInterfaceDecl ModuleDeclTokens(delim) { $1 ++ $2}
| GenericInterfaceDecl delim { $1 } | GenericInterfaceDecl DTDelim(delim) { $1 ++ [$2] }
GenericInterfaceDecl :: { [DeclToken] } GenericInterfaceDecl :: { [DeclToken] }
: "interface" IdentifierP { [DTType (tokenPosition $1) (\Unspecified -> InterfaceT "" ""), uncurry DTIdent $2] } : "interface" IdentifierP { [DTType (tokenPosition $1) (\Unspecified -> InterfaceT "" ""), uncurry DTIdent $2] }
......
...@@ -45,7 +45,7 @@ module Language.SystemVerilog.Parser.ParseDecl ...@@ -45,7 +45,7 @@ module Language.SystemVerilog.Parser.ParseDecl
, parseDTsAsDeclsOrAsgns , parseDTsAsDeclsOrAsgns
) where ) where
import Data.List (findIndex, findIndices, partition, uncons) import Data.List (findIndex, partition, uncons)
import Language.SystemVerilog.AST import Language.SystemVerilog.AST
import Language.SystemVerilog.Parser.Tokens (Position(..)) import Language.SystemVerilog.Parser.Tokens (Position(..))
...@@ -57,7 +57,7 @@ data DeclToken ...@@ -57,7 +57,7 @@ data DeclToken
| DTConst Position | DTConst Position
| DTVar Position | DTVar Position
| DTAsgn Position AsgnOp (Maybe Timing) Expr | DTAsgn Position AsgnOp (Maybe Timing) Expr
| DTRange Position (PartSelectMode, Range) | DTRange Position PartSelectMode Range
| DTIdent Position Identifier | DTIdent Position Identifier
| DTPSIdent Position Identifier Identifier | DTPSIdent Position Identifier Identifier
| DTCSIdent Position Identifier [ParamBinding] Identifier | DTCSIdent Position Identifier [ParamBinding] Identifier
...@@ -73,59 +73,34 @@ data DeclToken ...@@ -73,59 +73,34 @@ data DeclToken
| DTSigning Position Signing | DTSigning Position Signing
| DTLifetime Position Lifetime | DTLifetime Position Lifetime
| DTAttr Position Attr | DTAttr Position Attr
deriving (Show, Eq) | DTEnd Position Char
deriving Eq
-- 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
forbidNonEqAsgn :: [DeclToken] -> a -> a
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
-- [PUBLIC]: parser for module port declarations, including interface ports -- [PUBLIC]: parser for module port declarations, including interface ports
-- Example: `input foo, bar, One inst` -- Example: `input foo, bar, One inst`
parseDTsAsPortDecls :: [DeclToken] -> ([Identifier], [ModuleItem]) parseDTsAsPortDecls :: [DeclToken] -> ([Identifier], [ModuleItem])
parseDTsAsPortDecls pieces = parseDTsAsPortDecls = parseDTsAsPortDecls' . dropTrailingComma
parseDTsAsPortDecls' $ where
case last pieces of dropTrailingComma :: [DeclToken] -> [DeclToken]
DTComma{} -> init pieces dropTrailingComma [] = []
_ -> pieces dropTrailingComma [DTComma{}, end @ DTEnd{}] = [end]
dropTrailingComma (tok : toks) = tok : dropTrailingComma toks
-- internal parseDTsAsPortDecls after the removal of an optional trailing comma -- internal parseDTsAsPortDecls after the removal of an optional trailing comma
parseDTsAsPortDecls' :: [DeclToken] -> ([Identifier], [ModuleItem]) parseDTsAsPortDecls' :: [DeclToken] -> ([Identifier], [ModuleItem])
parseDTsAsPortDecls' pieces = parseDTsAsPortDecls' pieces =
forbidNonEqAsgn pieces `seq`
if isSimpleList if isSimpleList
then (simpleIdents, []) then (simpleIdents, [])
else (portNames declarations, applyAttrs [] pieces declarations) else (portNames declarations, applyAttrs [] pieces declarations)
where where
commaIdxs = findIndices isComma pieces maybeSimpleIdents = parseDTsAsIdents pieces
identIdxs = findIndices isIdent pieces Just simpleIdents = maybeSimpleIdents
isSimpleList = isSimpleList = maybeSimpleIdents /= Nothing
all even identIdxs &&
all odd commaIdxs &&
odd (length pieces) &&
length pieces == length commaIdxs + length identIdxs
simpleIdents = map extractIdent $ filter isIdent pieces
declarations = propagateDirections Input $ parseDTsAsDecls pieces'
extractIdent = \(DTIdent _ x) -> x declarations = propagateDirections Input $ parseDTsAsDecls pieces'
pieces' = filter (not . isDTAttr) pieces pieces' = filter (not . isAttr) pieces
isDTAttr :: DeclToken -> Bool
isDTAttr DTAttr{} = True
isDTAttr _ = False
propagateDirections :: Direction -> [Decl] -> [Decl] propagateDirections :: Direction -> [Decl] -> [Decl]
propagateDirections dir (decl @ (Variable _ InterfaceT{} _ _ _) : decls) = propagateDirections dir (decl @ (Variable _ InterfaceT{} _ _ _) : decls) =
...@@ -149,12 +124,9 @@ parseDTsAsPortDecls' pieces = ...@@ -149,12 +124,9 @@ parseDTsAsPortDecls' pieces =
portName :: Decl -> Identifier portName :: Decl -> Identifier
portName (Variable _ _ ident _ _) = ident portName (Variable _ _ ident _ _) = ident
portName (Net _ _ _ _ ident _ _) = ident portName (Net _ _ _ _ ident _ _) = ident
portName CommentDecl{} = "" portName _ = ""
portName decl =
error $ "unexpected non-variable port declaration: " ++ (show decl)
applyAttrs :: [Attr] -> [DeclToken] -> [Decl] -> [ModuleItem] applyAttrs :: [Attr] -> [DeclToken] -> [Decl] -> [ModuleItem]
applyAttrs _ [] [] = []
applyAttrs _ tokens (CommentDecl c : decls) = applyAttrs _ tokens (CommentDecl c : decls) =
MIPackageItem (Decl $ CommentDecl c) : applyAttrs [] tokens decls MIPackageItem (Decl $ CommentDecl c) : applyAttrs [] tokens decls
applyAttrs attrs (DTAttr _ attr : tokens) decls = applyAttrs attrs (DTAttr _ attr : tokens) decls =
...@@ -165,41 +137,53 @@ parseDTsAsPortDecls' pieces = ...@@ -165,41 +137,53 @@ parseDTsAsPortDecls' pieces =
wrapDecl attrs decl : applyAttrs attrs tokens decls wrapDecl attrs decl : applyAttrs attrs tokens decls
applyAttrs attrs (_ : tokens) decls = applyAttrs attrs (_ : tokens) decls =
applyAttrs attrs tokens decls applyAttrs attrs tokens decls
applyAttrs _ [] _ = error "applyAttrs internal invariant failed" applyAttrs _ [] _ = undefined
wrapDecl :: [Attr] -> Decl -> ModuleItem wrapDecl :: [Attr] -> Decl -> ModuleItem
wrapDecl attrs decl = foldr MIAttr (MIPackageItem $ Decl decl) attrs wrapDecl attrs decl = foldr MIAttr (MIPackageItem $ Decl decl) attrs
-- internal utility for a simple list of port identifiers
parseDTsAsIdents :: [DeclToken] -> Maybe [Identifier]
parseDTsAsIdents [DTIdent _ x, DTEnd _ _] = Just [x]
parseDTsAsIdents [_, _] = Nothing
parseDTsAsIdents (DTIdent _ x : DTComma _ : rest) =
fmap (x :) (parseDTsAsIdents rest)
parseDTsAsIdents _ = Nothing
-- [PUBLIC]: parser for single (semicolon-terminated) declarations (including -- [PUBLIC]: parser for single (semicolon-terminated) declarations (including
-- parameters) and module instantiations -- parameters) and module instantiations
parseDTsAsModuleItems :: [DeclToken] -> [ModuleItem] parseDTsAsModuleItems :: [DeclToken] -> [ModuleItem]
parseDTsAsModuleItems tokens = parseDTsAsModuleItems tokens =
forbidNonEqAsgn tokens `seq` if maybeElabTask /= Nothing then
if isElabTask $ head tokens then [elabTask]
asElabTask tokens
else if any isPorts tokens then else if any isPorts tokens then
parseDTsAsIntantiations tokens parseDTsAsIntantiations tokens
else else
map (MIPackageItem . Decl) $ parseDTsAsDecl tokens map (MIPackageItem . Decl) $ parseDTsAsDecl tokens
where where
isElabTask :: DeclToken -> Bool Just elabTask = maybeElabTask
isElabTask (DTIdent _ x) = elem x elabTasks maybeElabTask = asElabTask tokens
where elabTasks = ["$fatal", "$error", "$warning", "$info"]
isElabTask _ = False -- internal; attempt to parse an elaboration system task
asElabTask :: [DeclToken] -> Maybe ModuleItem
-- internal; approximates the behavior of the elaboration system tasks asElabTask tokens = do
asElabTask :: [DeclToken] -> [ModuleItem] DTIdent _ x @ ('$' : _) <- return $ head tokens
asElabTask [DTIdent _ name, DTPorts _ args] = severity <- lookup x elabTasks
if name == "$info" Just $ ElabTask severity args
then [] -- just drop them for simplicity where
else [Instance "ThisModuleDoesNotExist" [] name' [] args] args =
where name' = "__sv2v_elab_" ++ tail name case tail tokens of
asElabTask [DTIdent pos name] = [DTEnd{}] -> Args [] []
asElabTask [DTIdent pos name, DTPorts pos []] [DTPorts _ ports, DTEnd{}] -> portsToArgs ports
asElabTask tokens = DTPorts{} : tok : _ -> parseError tok msg
error $ "could not parse elaboration system task: " ++ show tokens toks -> parseError (head toks) msg
msg = "unexpected token after elaboration system task"
-- lookup table for elaboration system task severities
elabTasks :: [(String, Severity)]
elabTasks = map (\x -> (show x, x))
[SeverityInfo, SeverityWarning, SeverityError, SeverityFatal]
-- internal; parser for module instantiations -- internal; parser for module instantiations
parseDTsAsIntantiations :: [DeclToken] -> [ModuleItem] parseDTsAsIntantiations :: [DeclToken] -> [ModuleItem]
...@@ -207,18 +191,12 @@ parseDTsAsIntantiations (DTIdent _ name : DTParams _ params : tokens) = ...@@ -207,18 +191,12 @@ parseDTsAsIntantiations (DTIdent _ name : DTParams _ params : tokens) =
step tokens step tokens
where where
step :: [DeclToken] -> [ModuleItem] step :: [DeclToken] -> [ModuleItem]
step [] = parseError endTok "unexpected end of instantiation list" step [] = []
step toks = inst : rest step toks = inst : step restToks
where where
(delimTok, rest) =
if null restToks
then (endTok, [])
else (head restToks, step $ tail restToks)
inst = Instance name params x rs p inst = Instance name params x rs p
(x, rs, p) = parseDTsAsIntantiation instToks delimTok (x, rs, p) = parseDTsAsIntantiation instToks delimTok
(instToks, restToks) = break isComma toks (instToks, delimTok : restToks) = break isCommaOrEnd toks
-- TODO: all public interfaces should take the ending token
endTok = last tokens
parseDTsAsIntantiations (DTIdent pos name : tokens) = parseDTsAsIntantiations (DTIdent pos name : tokens) =
parseDTsAsIntantiations $ DTIdent pos name : DTParams pos [] : tokens parseDTsAsIntantiations $ DTIdent pos name : DTParams pos [] : tokens
parseDTsAsIntantiations tokens = parseDTsAsIntantiations tokens =
...@@ -230,16 +208,20 @@ parseDTsAsIntantiation :: [DeclToken] -> DeclToken ...@@ -230,16 +208,20 @@ parseDTsAsIntantiation :: [DeclToken] -> DeclToken
-> (Identifier, [Range], [PortBinding]) -> (Identifier, [Range], [PortBinding])
parseDTsAsIntantiation l0 delimTok = parseDTsAsIntantiation l0 delimTok =
if null l0 then if null l0 then
parseError delimTok "expected instantiation before delimiter" parseError delimTok $ "expected instantiation before " ++ delimStr
else if not (isIdent nameTok) then else if not (isIdent nameTok) then
parseError nameTok "expected instantiation name" parseError nameTok "expected instantiation name"
else if null l1 then else if null l1 then
parseError delimTok "expected port connections before delimiter" parseError delimTok $ "expected port connections before " ++ delimStr
else if seq ranges not (isPorts portsTok) then else if seq ranges not (isPorts portsTok) then
parseError portsTok "expected port connections" parseError portsTok "expected port connections"
else else
(name, ranges, ports) (name, ranges, ports)
where where
delimChar = case delimTok of
DTEnd _ char -> char
_ -> ','
delimStr = ['\'', delimChar, '\'']
Just (nameTok, l1) = uncons l0 Just (nameTok, l1) = uncons l0
rangeToks = init l1 rangeToks = init l1
portsTok = last l1 portsTok = last l1
...@@ -247,7 +229,7 @@ parseDTsAsIntantiation l0 delimTok = ...@@ -247,7 +229,7 @@ parseDTsAsIntantiation l0 delimTok =
DTPorts _ ports = portsTok DTPorts _ ports = portsTok
ranges = map asRange rangeToks ranges = map asRange rangeToks
asRange :: DeclToken -> Range asRange :: DeclToken -> Range
asRange (DTRange _ (NonIndexed, s)) = s asRange (DTRange _ NonIndexed s) = s
asRange (DTBit _ s) = (RawNum 0, BinOp Sub s (RawNum 1)) asRange (DTBit _ s) = (RawNum 0, BinOp Sub s (RawNum 1))
asRange tok = parseError tok "expected instantiation dimensions" asRange tok = parseError tok "expected instantiation dimensions"
...@@ -255,61 +237,61 @@ parseDTsAsIntantiation l0 delimTok = ...@@ -255,61 +237,61 @@ parseDTsAsIntantiation l0 delimTok =
-- [PUBLIC]: parser for generic, comma-separated declarations -- [PUBLIC]: parser for generic, comma-separated declarations
parseDTsAsDecls :: [DeclToken] -> [Decl] parseDTsAsDecls :: [DeclToken] -> [Decl]
parseDTsAsDecls tokens = parseDTsAsDecls tokens =
forbidNonEqAsgn tokens `seq` concatMap finalize $ parseDTsAsComponents tokens
concat $ map finalize $ parseDTsAsComponents tokens
-- internal; used for "single" declarations, i.e., declarations appearing -- internal; used for "single" declarations, i.e., declarations appearing
-- outside of a port list -- outside of a port list
parseDTsAsDecl :: [DeclToken] -> [Decl] parseDTsAsDecl :: [DeclToken] -> [Decl]
parseDTsAsDecl tokens = parseDTsAsDecl tokens =
if length components /= 1 if null rest
then parseError tok $ "unexpected comma-separated declarations" then finalize component
else finalize $ head components else parseError (head rest) "unexpected token in declaration"
where where (component, rest) = parseDTsAsComponent tokens
components = parseDTsAsComponents tokens
_ : (pos, _, _) : _ = components
tok = DTComma pos
-- [PUBLIC]: parser for single block item declarations or assign or arg-less -- [PUBLIC]: parser for single block item declarations or assign or arg-less
-- subroutine call statements -- subroutine call statements
parseDTsAsDeclOrStmt :: [DeclToken] -> ([Decl], [Stmt]) parseDTsAsDeclOrStmt :: [DeclToken] -> ([Decl], [Stmt])
parseDTsAsDeclOrStmt (DTAsgn pos (AsgnOp op) mt e : tok : toks) =
parseDTsAsDeclOrStmt $ (tok : toks) ++ [DTAsgn pos (AsgnOp op) mt e]
parseDTsAsDeclOrStmt tokens = parseDTsAsDeclOrStmt tokens =
if not hasLeadingDecl if declLookahead tokens
then ([], [traceStmt pos, stmt]) then (parseDTsAsDecl tokens, [])
else (parseDTsAsDecl tokens, []) else ([], parseDTsAsStmt $ shiftIncOrDec tokens)
-- check if the necessary tokens for a complete declaration exist at the
-- beginning of the given token list
declLookahead :: [DeclToken] -> Bool
declLookahead l0 =
l0 /= l5 && tripLookahead l5
where where
pos = tokPos $ last tokens (_, l1) = takeDir l0
stmt = case last tokens of
DTAsgn _ op mt e -> Asgn op mt lhs e
DTPorts _ ports -> asSubroutine lhsToks (portsToArgs ports)
_ -> asSubroutine tokens (Args [] [])
lhsToks = init tokens
lhs = case takeLHS lhsToks of
Nothing -> error $ "could not parse as LHS: " ++ show lhsToks
Just l -> l
hasLeadingDecl = tokens /= l5 && tripLookahead l5
(_, l1) = takeDir tokens
(_, l2) = takeLifetime l1 (_, l2) = takeLifetime l1
(_, l3) = takeVarOrNet l2 (_, l3) = takeVarOrNet l2
(_, l4) = takeType l3 (_, l4) = takeType l3
(_, l5) = takeRanges l4 (_, l5) = takeRanges l4
traceStmt :: Position -> Stmt -- internal; parser for leading statements in a procedural block
traceStmt pos = CommentStmt $ "Trace: " ++ show pos parseDTsAsStmt :: [DeclToken] -> [Stmt]
parseDTsAsStmt l0 =
[traceStmt $ head l0, stmt]
where
(lhs, _) = takeLHS l0
(expr, l1) = takeExpr l0
stmt = case init l1 of
[DTAsgn _ op mt e] -> Asgn op mt lhs e
[DTPorts _ ports] -> Subroutine expr (portsToArgs ports)
[] -> Subroutine expr (Args [] [])
tok : _ -> parseError tok "unexpected statement token"
traceStmt :: DeclToken -> Stmt
traceStmt tok = CommentStmt $ "Trace: " ++ show (tokPos tok)
-- read the given tokens as the root of a subroutine invocation -- read the given tokens as the root of a subroutine invocation
asSubroutine :: [DeclToken] -> Args -> Stmt takeExpr :: [DeclToken] -> (Expr, [DeclToken])
asSubroutine [DTIdent _ x] = Subroutine $ Ident x takeExpr (DTPSIdent _ p x : toks) = (PSIdent p x, toks)
asSubroutine [DTPSIdent _ p x] = Subroutine $ PSIdent p x takeExpr (DTCSIdent _ c p x : toks) = (CSIdent c p x, toks)
asSubroutine [DTCSIdent _ c p x] = Subroutine $ CSIdent c p x takeExpr toks = (lhsToExpr lhs, rest)
asSubroutine tokens = where (lhs, rest) = takeLHS toks
case takeLHS tokens of
Just lhs -> Subroutine $ lhsToExpr lhs
Nothing -> error $ "invalid block item decl or stmt: " ++ show tokens
-- converts port bindings to call args -- converts port bindings to call args
portsToArgs :: [PortBinding] -> Args portsToArgs :: [PortBinding] -> Args
...@@ -324,66 +306,68 @@ portsToArgs bindings = ...@@ -324,66 +306,68 @@ portsToArgs bindings =
-- is only used for `for` loop initialization lists -- is only used for `for` loop initialization lists
parseDTsAsDeclsOrAsgns :: [DeclToken] -> Either [Decl] [(LHS, Expr)] parseDTsAsDeclsOrAsgns :: [DeclToken] -> Either [Decl] [(LHS, Expr)]
parseDTsAsDeclsOrAsgns tokens = parseDTsAsDeclsOrAsgns tokens =
forbidNonEqAsgn tokens `seq` if declLookahead tokens
if hasLeadingAsgn || tripLookahead tokens then Left decls
then Right $ parseDTsAsAsgns tokens else Right asgns
else Left $ map checkDecl $ parseDTsAsDecls tokens
where where
hasLeadingAsgn = decls = concatMap finalize components
-- if there is an asgn token before the next comma components = map checkComponent $ parseDTsAsComponents tokens
case (findIndex isComma tokens, findIndex isAsgnToken tokens) of asgns = parseDTsAsAsgns $ shiftIncOrDec tokens
(Just a, Just b) -> a > b checkComponent :: Component -> Component
(Nothing, Just _) -> True checkComponent (pos, base, trips) =
_ -> False (pos, base, map (checkTriplet pos) trips)
checkDecl :: Decl -> Decl checkTriplet :: Position -> Triplet -> Triplet
checkDecl (decl @ (Variable _ _ _ _ Nil)) = checkTriplet pos (x, _, Nil) =
error $ "for loop declaration missing initialization: " parseError pos $ "for loop declaration of " ++ show x
++ init (show decl) ++ " is missing initialization"
checkDecl decl = decl checkTriplet _ trip = trip
-- internal parser for basic assignment lists -- internal parser for basic assignment lists
parseDTsAsAsgns :: [DeclToken] -> [(LHS, Expr)] parseDTsAsAsgns :: [DeclToken] -> [(LHS, Expr)]
parseDTsAsAsgns tokens = parseDTsAsAsgns tokens =
case l1 of if not (isAsgn asgnTok) then
[] -> [asgn] parseError asgnTok "expected assignment operator"
DTComma{} : remaining -> asgn : parseDTsAsAsgns remaining else if mt /= Nothing then
_ -> error $ "bad assignment tokens: " ++ show tokens unexpected "timing modifier"
else (lhs, expr) : case head remaining of
DTEnd{} -> []
DTComma{} -> parseDTsAsAsgns $ tail remaining
tok -> parseError tok "expected ',' or ';'"
where where
(lhsToks, l0) = break isDTAsgn tokens (lhs, asgnTok : remaining) = takeLHS tokens
lhs = case takeLHS lhsToks of DTAsgn _ op mt rhs = asgnTok
Nothing -> error $ "could not parse as LHS: " ++ show lhsToks expr = case op of
Just l -> l AsgnOpEq -> rhs
DTAsgn _ AsgnOpEq Nothing expr : l1 = l0 AsgnOpNonBlocking -> unexpected "non-blocking assignment"
asgn = (lhs, expr) AsgnOp binop -> BinOp binop (lhsToExpr lhs) rhs
isDTAsgn :: DeclToken -> Bool unexpected surprise = parseError asgnTok $
isDTAsgn (DTAsgn _ _ Nothing _) = True "unexpected " ++ surprise ++ " in for loop initialization"
isDTAsgn _ = False
shiftIncOrDec :: [DeclToken] -> [DeclToken]
isAsgnToken :: DeclToken -> Bool shiftIncOrDec (tok @ (DTAsgn _ AsgnOp{} _ _) : toks) =
isAsgnToken (DTBit{} ) = True before ++ tok : delim : shiftIncOrDec after
isAsgnToken (DTConcat{}) = True where (before, delim : after) = break isCommaOrEnd toks
isAsgnToken (DTStream{}) = True shiftIncOrDec [] = []
isAsgnToken (DTDot{} ) = True shiftIncOrDec toks =
isAsgnToken (DTAsgn _ op _ _) = op /= AsgnOpEq before ++ delim : shiftIncOrDec after
isAsgnToken _ = False where (before, delim : after) = break isCommaOrEnd toks
takeLHS :: [DeclToken] -> Maybe LHS takeLHS :: [DeclToken] -> (LHS, [DeclToken])
takeLHS [] = Nothing takeLHS tokens = takeLHSStep (takeLHSStart tok) toks
takeLHS (t : ts) = where tok : toks = tokens
foldl takeLHSStep (takeLHSStart t) ts
takeLHSStart :: DeclToken -> LHS
takeLHSStart :: DeclToken -> Maybe LHS takeLHSStart (DTConcat _ lhss) = LHSConcat lhss
takeLHSStart (DTConcat _ lhss) = Just $ LHSConcat lhss takeLHSStart (DTStream _ o e lhss) = LHSStream o e lhss
takeLHSStart (DTStream _ o e lhss) = Just $ LHSStream o e lhss takeLHSStart (DTIdent _ x ) = LHSIdent x
takeLHSStart (DTIdent _ x ) = Just $ LHSIdent x takeLHSStart tok = parseError tok "expected primary token or type"
takeLHSStart _ = Nothing
takeLHSStep :: LHS -> [DeclToken] -> (LHS, [DeclToken])
takeLHSStep :: Maybe LHS -> DeclToken -> Maybe LHS takeLHSStep curr (DTBit _ e : toks) = takeLHSStep (LHSBit curr e ) toks
takeLHSStep (Just curr) (DTBit _ e ) = Just $ LHSBit curr e takeLHSStep curr (DTRange _ m r : toks) = takeLHSStep (LHSRange curr m r) toks
takeLHSStep (Just curr) (DTRange _ (m,r)) = Just $ LHSRange curr m r takeLHSStep curr (DTDot _ x : toks) = takeLHSStep (LHSDot curr x ) toks
takeLHSStep (Just curr) (DTDot _ x ) = Just $ LHSDot curr x takeLHSStep lhs toks = (lhs, toks)
takeLHSStep _ _ = Nothing
-- batches together separate declaration lists -- batches together separate declaration lists
...@@ -404,13 +388,11 @@ parseDTsAsComponents tokens = ...@@ -404,13 +388,11 @@ parseDTsAsComponents tokens =
where (component, tokens') = parseDTsAsComponent tokens where (component, tokens') = parseDTsAsComponent tokens
parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken]) parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken])
parseDTsAsComponent [] = error "parseDTsAsComponent unexpected end of tokens"
parseDTsAsComponent l0 = parseDTsAsComponent l0 =
if l /= Nothing && l /= Just Automatic then if l /= Nothing && l /= Just Automatic then
error $ "unexpected non-automatic lifetime: " ++ show l0 parseError (head l1) "unexpected non-automatic lifetime"
else if dir == Local && length l2 == length l5 then else if dir == Local && length l2 == length l5 then
error $ "declaration(s) missing type information: " parseError (head l0) "declaration missing type information"
++ show (position, tps)
else else
(component, l6) (component, l6)
where where
...@@ -419,50 +401,37 @@ parseDTsAsComponent l0 = ...@@ -419,50 +401,37 @@ parseDTsAsComponent l0 =
(von, l3) = takeVarOrNet l2 (von, l3) = takeVarOrNet l2
(tf , l4) = takeType l3 (tf , l4) = takeType l3
(rs , l5) = takeRanges l4 (rs , l5) = takeRanges l4
(tps, l6) = takeTrips l5 True (tps, l6) = takeTrips l5
position = tokPos $ head l0 position = tokPos $ head l0
base = von dir $ tf rs base = von dir $ tf rs
component = (position, base, tps) component = (position, base, tps)
takeTrips :: [DeclToken] -> Bool -> ([Triplet], [DeclToken]) takeTrips :: [DeclToken] -> ([Triplet], [DeclToken])
takeTrips [] True = error "incomplete declaration" takeTrips l0 =
takeTrips [] False = ([], []) (trip : trips, l5)
takeTrips l0 force =
if not force && not (tripLookahead l0)
then ([], l0)
else (trip : trips, l5)
where where
(x, l1) = takeIdent l0 (x, l1) = takeIdent l0
(a, l2) = takeRanges l1 (a, l2) = takeRanges l1
(e, l3) = takeAsgn l2 (e, l3) = takeAsgn l2
(_, l4) = takeComma l3 l4 = takeCommaOrEnd l3
trip = (x, a, e) trip = (x, a, e)
(trips, l5) = takeTrips l4 False (trips, l5) =
if tripLookahead l4
then takeTrips l4
else ([], l4)
tripLookahead :: [DeclToken] -> Bool tripLookahead :: [DeclToken] -> Bool
tripLookahead [] = False
tripLookahead l0 = tripLookahead l0 =
not (null l0) &&
-- every triplet *must* begin with an identifier -- every triplet *must* begin with an identifier
if not (isIdent $ head l0) then isIdent (head l0) &&
False -- expecting to see a comma or the ending token after the identifier and
-- if the identifier is the last token, or if it assigned a value, then we -- optional ranges and/or assignment
-- know we must have a valid triplet ahead isCommaOrEnd (head l3)
else if null l1 || asgn /= Nil then
True
-- 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
-- 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) && (isComma $ head l3)
where where
(_ , l1) = takeIdent l0 (_, l1) = takeIdent l0
(_ , l2) = takeRanges l1 (_, l2) = takeRanges l1
(asgn, l3) = takeAsgn l2 (_, l3) = takeAsgn l2
takeDir :: [DeclToken] -> (Direction, [DeclToken]) takeDir :: [DeclToken] -> (Direction, [DeclToken])
takeDir (DTDir _ dir : rest) = (dir , rest) takeDir (DTDir _ dir : rest) = (dir , rest)
...@@ -473,8 +442,8 @@ takeLifetime (DTLifetime _ l : rest) = (Just l, rest) ...@@ -473,8 +442,8 @@ takeLifetime (DTLifetime _ l : rest) = (Just l, rest)
takeLifetime rest = (Nothing, rest) takeLifetime rest = (Nothing, rest)
takeVarOrNet :: [DeclToken] -> (Direction -> Type -> DeclBase, [DeclToken]) takeVarOrNet :: [DeclToken] -> (Direction -> Type -> DeclBase, [DeclToken])
takeVarOrNet (DTConst{} : tok @ DTConst{} : _) = takeVarOrNet (DTConst{} : DTConst pos : _) =
parseError tok "duplicate const modifier" parseError pos "duplicate const modifier"
takeVarOrNet (DTConst _ : tokens) = takeVarOrNet tokens takeVarOrNet (DTConst _ : tokens) = takeVarOrNet tokens
takeVarOrNet (DTNet _ n s : tokens) = (\d -> Net d n s, tokens) takeVarOrNet (DTNet _ n s : tokens) = (\d -> Net d n s, tokens)
takeVarOrNet tokens = (Variable, tokens) takeVarOrNet tokens = (Variable, tokens)
...@@ -499,8 +468,8 @@ takeType (DTIdent pos tn : rest) = ...@@ -499,8 +468,8 @@ takeType (DTIdent pos tn : rest) =
(_, Nothing) -> True (_, Nothing) -> True
-- if comma is first, then this ident is a declaration -- if comma is first, then this ident is a declaration
(Just a, Just b) -> a < b (Just a, Just b) -> a < b
takeType (DTVar{} : tok @ DTVar{} : _) = takeType (DTVar{} : DTVar pos : _) =
parseError tok "duplicate var modifier" parseError pos "duplicate var modifier"
takeType (DTVar _ : rest) = takeType (DTVar _ : rest) =
case tf [] of case tf [] of
Implicit sg [] -> (IntegerVector TLogic sg, rest') Implicit sg [] -> (IntegerVector TLogic sg, rest')
...@@ -509,19 +478,18 @@ takeType (DTVar _ : rest) = ...@@ -509,19 +478,18 @@ takeType (DTVar _ : rest) =
takeType rest = (Implicit Unspecified, rest) takeType rest = (Implicit Unspecified, rest)
takeRanges :: [DeclToken] -> ([Range], [DeclToken]) takeRanges :: [DeclToken] -> ([Range], [DeclToken])
takeRanges [] = ([], []) takeRanges tokens =
takeRanges (token : tokens) = case head tokens of
case token of DTRange _ NonIndexed r -> (r : rs, rest)
DTRange _ (NonIndexed, r) -> (r : rs, rest ) DTBit _ s -> (asRange s : rs, rest)
DTBit _ s -> (asRange s : rs, rest ) DTAutoDim _ ->
DTAutoDim _ -> case head $ tail tokens of
case rest of DTAsgn _ AsgnOpEq Nothing (Pattern l) -> autoDim l
(DTAsgn _ AsgnOpEq Nothing (Pattern l) : _) -> autoDim l DTAsgn _ AsgnOpEq Nothing (Concat l) -> autoDim l
(DTAsgn _ AsgnOpEq Nothing (Concat l) : _) -> autoDim l _ -> ([], tokens)
_ -> ([] , token : tokens) _ -> ([], tokens)
_ -> ([] , token : tokens)
where where
(rs, rest) = takeRanges tokens (rs, rest) = takeRanges $ tail tokens
asRange s = (RawNum 0, BinOp Sub s (RawNum 1)) asRange s = (RawNum 0, BinOp Sub s (RawNum 1))
autoDim :: [a] -> ([Range], [DeclToken]) autoDim :: [a] -> ([Range], [DeclToken])
autoDim l = autoDim l =
...@@ -531,35 +499,53 @@ takeRanges (token : tokens) = ...@@ -531,35 +499,53 @@ takeRanges (token : tokens) =
lo = RawNum 0 lo = RawNum 0
hi = RawNum $ fromIntegral $ n - 1 hi = RawNum $ fromIntegral $ n - 1
-- 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.
takeAsgn :: [DeclToken] -> (Expr, [DeclToken]) takeAsgn :: [DeclToken] -> (Expr, [DeclToken])
takeAsgn (DTAsgn _ op Nothing e : rest) = takeAsgn (tok @ (DTAsgn _ op mt e) : rest) =
if op == AsgnOpEq || op == AsgnOpNonBlocking if op == AsgnOpNonBlocking then
then (e , rest) unexpected "non-blocking assignment operator"
else (Nil, rest) else if op /= AsgnOpEq then
unexpected "binary assignment operator"
else if mt /= Nothing then
unexpected "timing modifier"
else
(e, rest)
where
unexpected surprise =
parseError tok $ "unexpected " ++ surprise ++ " in declaration"
takeAsgn rest = (Nil, rest) takeAsgn rest = (Nil, rest)
takeComma :: [DeclToken] -> (Bool, [DeclToken]) takeCommaOrEnd :: [DeclToken] -> [DeclToken]
takeComma [] = (False, []) takeCommaOrEnd tokens =
takeComma (DTComma{} : rest) = (True, rest) if isCommaOrEnd tok
takeComma toks = error $ "expected comma or end of decl, got: " ++ show toks then toks
else parseError tok "expected comma or end of declarations"
where tok : toks = tokens
takeIdent :: [DeclToken] -> (Identifier, [DeclToken]) takeIdent :: [DeclToken] -> (Identifier, [DeclToken])
takeIdent (DTIdent _ x : rest) = (x, rest) takeIdent (DTIdent _ x : rest) = (x, rest)
takeIdent tokens = error $ "takeIdent didn't find identifier: " ++ show tokens takeIdent tokens = parseError (head tokens) "expected identifier"
isAttr :: DeclToken -> Bool
isAttr DTAttr{} = True
isAttr _ = False
isAsgn :: DeclToken -> Bool
isAsgn DTAsgn{} = True
isAsgn _ = False
isIdent :: DeclToken -> Bool isIdent :: DeclToken -> Bool
isIdent (DTIdent{}) = True isIdent DTIdent{} = True
isIdent _ = False isIdent _ = False
isComma :: DeclToken -> Bool isComma :: DeclToken -> Bool
isComma (DTComma{}) = True isComma DTComma{} = True
isComma _ = False isComma _ = False
isCommaOrEnd :: DeclToken -> Bool
isCommaOrEnd DTEnd{} = True
isCommaOrEnd tok = isComma tok
isPorts :: DeclToken -> Bool isPorts :: DeclToken -> Bool
isPorts DTPorts{} = True isPorts DTPorts{} = True
isPorts _ = False isPorts _ = False
...@@ -570,7 +556,7 @@ tokPos (DTAutoDim p) = p ...@@ -570,7 +556,7 @@ tokPos (DTAutoDim p) = p
tokPos (DTConst p) = p tokPos (DTConst p) = p
tokPos (DTVar p) = p tokPos (DTVar p) = p
tokPos (DTAsgn p _ _ _) = p tokPos (DTAsgn p _ _ _) = p
tokPos (DTRange p _) = p tokPos (DTRange p _ _) = p
tokPos (DTIdent p _) = p tokPos (DTIdent p _) = p
tokPos (DTPSIdent p _ _) = p tokPos (DTPSIdent p _ _) = p
tokPos (DTCSIdent p _ _ _) = p tokPos (DTCSIdent p _ _ _) = p
...@@ -586,7 +572,13 @@ tokPos (DTDot p _) = p ...@@ -586,7 +572,13 @@ tokPos (DTDot p _) = p
tokPos (DTSigning p _) = p tokPos (DTSigning p _) = p
tokPos (DTLifetime p _) = p tokPos (DTLifetime p _) = p
tokPos (DTAttr p _) = p tokPos (DTAttr p _) = p
tokPos (DTEnd p _) = p
class Loc t where
parseError :: t -> String -> a
instance Loc Position where
parseError pos msg = error $ show pos ++ ": Parse error: " ++ msg
parseError :: DeclToken -> String -> a instance Loc DeclToken where
parseError tok msg = error $ show pos ++ ": Parse error: " ++ msg parseError = parseError . tokPos
where pos = tokPos tok
module top;
if (1 == 0)
wire foo;
else
$info("foo");
endmodule
module top;
initial begin
integer x, y;
x = 0;
y = 3;
for (x += 1; x < y; x++)
$display("A x = %0d", x);
end
initial begin
integer x, y;
x = 0;
for (x += 1, y = 3; x < y; x++)
$display("B x = %0d", x);
end
initial begin
integer x, y;
x = 0;
for (y = 3, x += 1; x < y; x++)
$display("C x = %0d", x);
end
initial
for (integer x = 0, y = 3; x < y; x++)
$display("D x = %0d", x);
initial
for (integer x = 0, byte y = 3; x < y; x++)
$display("E x = %0d", x);
initial begin
integer x, y;
x = 0;
for (x++, y = 3; x < y; x++)
$display("F x = %0d", x);
end
initial begin
integer x, y;
x = 0;
for (y = 3, x++; x < y; x++)
$display("G x = %0d", x);
end
initial begin
integer x, y;
x = 0;
for (--x, y = 3; x < y; x++)
$display("H x = %0d", x);
end
initial begin
integer x, y;
x = 0;
for (y = 3, --x; x < y; x++)
$display("I x = %0d", x);
end
initial begin
integer x, y;
x = 0;
y = 2;
for (--y, ++y, y++, ++x, --x, --x; x < y; x++)
$display("J x = %0d", x);
end
endmodule
module top;
`define LOOP(ID, START) \
x = 0; \
for (x = START; x < 3; x = x + 1) \
$display(`"ID x = %0d`", x);
initial begin : blk
integer x;
`LOOP(A, 1)
`LOOP(B, 1)
`LOOP(C, 1)
`LOOP(D, 0)
`LOOP(E, 0)
`LOOP(F, 1)
`LOOP(G, 1)
`LOOP(H, -1)
`LOOP(I, -1)
`LOOP(J, -1)
end
endmodule
// pattern: auto_dim_int\.sv:3:15: Parse error: expected comma or end of declarations
module top;
integer x [] = 1;
endmodule
// pattern: block_start_1\.sv:4:9: Parse error: expected primary token or type
module top;
initial begin
,;
end
endmodule
// pattern: block_start_2\.sv:4:9: Parse error: expected primary token or type
module top;
initial begin
= 1;
end
endmodule
// pattern: block_start_3\.sv:4:9: Parse error: expected primary token or type
module top;
initial begin
P::Q = 1;
end
endmodule
// pattern: block_start_4\.sv:4:11: Parse error: unexpected statement token
module top;
initial begin
a , ;
end
endmodule
// pattern: decl_bare\.sv:3:5: Parse error: declaration missing type information
module top; module top;
a;
endmodule endmodule
// pattern: decl_missing_comma\.sv:3:15: Parse error: expected comma or end of declarations
module top;
integer a b;
endmodule
// pattern: decl_trailing_comma\.sv:3:16: Parse error: unexpected token in declaration
module top;
integer a, ;
endmodule
// pattern: elab_task_stray_after_args\.sv:3:12: Parse error: unexpected token after elaboration system task
module top;
$info(), ;
endmodule
// pattern: elab_task_stray_before_args\.sv:3:11: Parse error: unexpected token after elaboration system task
module top;
$info , ();
endmodule
// pattern: elab_task_stray_no_args\.sv:3:11: Parse error: unexpected token after elaboration system task
module top;
$info , ;
endmodule
// pattern: for loop declaration missing initialization // pattern: for_loop_decl_no_init\.sv:4:14: Parse error: for loop declaration of "x" is missing initialization
module top; module top;
initial initial
for (integer x; x < 3; x = x + 1) for (integer x; x < 3; x = x + 1)
......
// pattern: for_loop_init_bare\.sv:3:19: Parse error: expected assignment operator
module top;
initial for (a,; 1; a++) ;
endmodule
// pattern: for_loop_init_delay\.sv:4:20: Parse error: unexpected timing modifier in for loop initialization
module top;
integer x;
initial for (x = #1 1; 1; x++) ;
endmodule
// pattern: for_loop_init_nblk\.sv:4:20: Parse error: unexpected non-blocking assignment in for loop initialization
module top;
integer x;
initial for (x <= 1; 1; x++) ;
endmodule
// pattern: for_loop_init_stray\.sv:3:22: Parse error: expected ',' or ';'
module top;
initial for (a++ b++; 1; a++) ;
endmodule
// pattern: instantiation_extra_comma\.sv:3:18: Parse error: expected instantiation before delimiter // pattern: instantiation_extra_comma\.sv:3:18: Parse error: expected instantiation before ','
module top; module top;
example a(), , b(); example a(), , b();
endmodule endmodule
// pattern: instantiation_missing_ports\.sv:3:14: Parse error: expected port connections before delimiter // pattern: instantiation_missing_ports\.sv:3:14: Parse error: expected port connections before ','
module top; module top;
example a, c(); example a, c();
endmodule endmodule
// pattern: instantiation_trailing_comma\.sv:3:16: Parse error: unexpected end of instantiation list // pattern: instantiation_trailing_comma\.sv:3:18: Parse error: expected instantiation before ';'
module top; module top;
example a(), ; example a(), ;
endmodule endmodule
// pattern: port_list_incomplete\.sv:2:17: Parse error: expected identifier
module top(input);
endmodule
// pattern: run_on_decl_item.sv:3:16: Parse error: unexpected comma-separated declarations // pattern: run_on_decl_item\.sv:3:16: Parse error: unexpected token in declaration
module top; module top;
integer x, byte y; integer x, byte y;
endmodule endmodule
// pattern: run_on_decl_stmt.sv:4:20: Parse error: unexpected comma-separated declarations // pattern: run_on_decl_stmt\.sv:4:20: Parse error: unexpected token in declaration
module top; module top;
initial begin initial begin
integer x, byte y; integer x, byte y;
......
module top;
$info;
$info("%b", 1);
$warning;
$warning("%b", 2);
$error;
$error("%b", 3);
$fatal;
$fatal("%b", 4);
endmodule
#!/bin/bash
addTest() {
test=$1
eval "test_$test() { assertConverts $test.sv; }"
suite_addTest test_$test
}
source ../lib/functions.sh
source ../lib/discover.sh
. shunit2
module top;
trireg (small) x;
trireg (medium) y;
trireg (large) z;
endmodule
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment