From 5fd21ebfb0176494392a4a55c2264c3b56d501c2 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 5 Jul 2021 18:00:12 -0400 Subject: [PATCH] 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 --- src/Convert/Traverse.hs | 5 + src/Language/SystemVerilog/AST/ModuleItem.hs | 18 +- src/Language/SystemVerilog/Parser/Parse.y | 15 +- .../SystemVerilog/Parser/ParseDecl.hs | 446 +++++++++--------- test/core/elab_task.sv | 6 - test/core/elab_task.v | 2 - test/core/for_loop_inits.sv | 58 +++ test/core/for_loop_inits.v | 20 + test/error/auto_dim_int.sv | 4 + test/error/block_start_1.sv | 6 + test/error/block_start_2.sv | 6 + test/error/block_start_3.sv | 6 + test/error/block_start_4.sv | 6 + test/error/decl_bare.sv | 4 + test/error/decl_missing_comma.sv | 4 + test/error/decl_trailing_comma.sv | 4 + test/error/elab_task_stray_after_args.sv | 4 + test/error/elab_task_stray_before_args.sv | 4 + test/error/elab_task_stray_no_args.sv | 4 + test/error/for_loop_decl_no_init.sv | 2 +- test/error/for_loop_init_bare.sv | 4 + test/error/for_loop_init_delay.sv | 5 + test/error/for_loop_init_nblk.sv | 5 + test/error/for_loop_init_stray.sv | 4 + test/error/instantiation_extra_comma.sv | 2 +- test/error/instantiation_missing_ports.sv | 2 +- test/error/instantiation_trailing_comma.sv | 2 +- test/error/port_list_incomplete.sv | 3 + test/error/run_on_decl_item.sv | 2 +- test/error/run_on_decl_stmt.sv | 2 +- test/nosim/elab_task.sv | 10 + test/nosim/run.sh | 12 + test/nosim/trireg_charge_strength.sv | 5 + 33 files changed, 433 insertions(+), 249 deletions(-) delete mode 100644 test/core/elab_task.sv delete mode 100644 test/core/elab_task.v create mode 100644 test/core/for_loop_inits.sv create mode 100644 test/core/for_loop_inits.v create mode 100644 test/error/auto_dim_int.sv create mode 100644 test/error/block_start_1.sv create mode 100644 test/error/block_start_2.sv create mode 100644 test/error/block_start_3.sv create mode 100644 test/error/block_start_4.sv create mode 100644 test/error/decl_bare.sv create mode 100644 test/error/decl_missing_comma.sv create mode 100644 test/error/decl_trailing_comma.sv create mode 100644 test/error/elab_task_stray_after_args.sv create mode 100644 test/error/elab_task_stray_before_args.sv create mode 100644 test/error/elab_task_stray_no_args.sv create mode 100644 test/error/for_loop_init_bare.sv create mode 100644 test/error/for_loop_init_delay.sv create mode 100644 test/error/for_loop_init_nblk.sv create mode 100644 test/error/for_loop_init_stray.sv create mode 100644 test/error/port_list_incomplete.sv create mode 100644 test/nosim/elab_task.sv create mode 100755 test/nosim/run.sh create mode 100644 test/nosim/trireg_charge_strength.sv diff --git a/src/Convert/Traverse.hs b/src/Convert/Traverse.hs index e9df917..d46ae64 100644 --- a/src/Convert/Traverse.hs +++ b/src/Convert/Traverse.hs @@ -625,6 +625,11 @@ traverseNodesM exprMapper declMapper typeMapper lhsMapper stmtMapper = a' <- traverseAssertionStmtsM stmtMapper a a'' <- traverseAssertionExprsM exprMapper 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 diff --git a/src/Language/SystemVerilog/AST/ModuleItem.hs b/src/Language/SystemVerilog/AST/ModuleItem.hs index fbd48d7..1632968 100644 --- a/src/Language/SystemVerilog/AST/ModuleItem.hs +++ b/src/Language/SystemVerilog/AST/ModuleItem.hs @@ -14,6 +14,7 @@ module Language.SystemVerilog.AST.ModuleItem , NInputGateKW (..) , NOutputGateKW (..) , AssignOption (..) + , Severity (..) ) where import Data.List (intercalate) @@ -24,7 +25,7 @@ import Language.SystemVerilog.AST.ShowHelp import Language.SystemVerilog.AST.Attr (Attr) import Language.SystemVerilog.AST.Decl (Direction) 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.LHS (LHS) import Language.SystemVerilog.AST.Stmt (Stmt, AssertionItem, Timing(Delay)) @@ -41,6 +42,7 @@ data ModuleItem | Modport Identifier [ModportDecl] | Initial Stmt | Final Stmt + | ElabTask Severity Args | MIPackageItem PackageItem | NInputGate NInputGateKW Expr Identifier LHS [Expr] | NOutputGate NOutputGateKW Expr Identifier [LHS] Expr @@ -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 (Initial s ) = printf "initial %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) = showGate kw d x $ show lhs : map show exprs show (NOutputGate kw d x lhss expr) = @@ -148,3 +151,16 @@ instance Show AssignOption where show AssignOptionNone = "" show (AssignOptionDelay de) = printf "#(%s)" (show de) 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" diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 1956095..5ee5190 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -401,7 +401,6 @@ time { Token Lit_time _ _ } -- operator precedences, from *lowest* to *highest* %nonassoc DefaultStrength %nonassoc DriveStrength ChargeStrength -%nonassoc Asgn %nonassoc NoElse %nonassoc "else" %right "|->" "|=>" "#-#" "#=#" @@ -630,17 +629,17 @@ Strength :: { Strength } DeclTokens(delim) :: { [DeclToken] } : DeclTokensBase(DeclTokens(delim), delim) { $1 } DeclTokensBase(repeat, delim) :: { [DeclToken] } - : DeclToken delim { [$1] } + : DeclToken DTDelim(delim) { [$1, $2] } | DeclToken repeat { [$1] ++ $2 } | IdentifierP ParamBindings repeat { [uncurry DTIdent $1, DTParams (fst $1) $2] ++ $3 } | DeclTokenAsgn "," repeat { [$1, DTComma (tokenPosition $2)] ++ $3 } - | DeclTokenAsgn delim { [$1] } + | DeclTokenAsgn DTDelim(delim) { [$1, $2] } DeclToken :: { DeclToken } : "," { DTComma $ tokenPosition $1 } | "[" "]" { DTAutoDim $ tokenPosition $1 } | "const" { DTConst $ tokenPosition $1 } | "var" { DTVar $ tokenPosition $1 } - | PartSelectP { uncurry DTRange $1 } + | PartSelectP { uncurry (DTRange $ fst $1) (snd $1) } | IdentifierP { uncurry DTIdent $1 } | DirectionP { uncurry DTDir $1 } | LHSConcatP { uncurry DTConcat $1 } @@ -655,21 +654,23 @@ DeclToken :: { DeclToken } | "{" StreamOp Concat "}" { DTStream (tokenPosition $1) $2 (RawNum 1) (map toLHS $3) } | "type" "(" Expr ")" { uncurry DTType $ makeTypeOf $1 $3 } | 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 ParamBindings "::" Identifier { uncurry DTCSIdent $1 $2 $4 } +DTDelim(delim) :: { DeclToken } + : delim { DTEnd (tokenPosition $1) (head $ tokenString $1) } DeclTokenAsgn :: { DeclToken } : "=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpEq $2 $3 } | AsgnBinOpP Expr { uncurry DTAsgn $1 Nothing $2 } + | "<=" opt(DelayOrEvent) Expr { DTAsgn (tokenPosition $1) AsgnOpNonBlocking $2 $3 } PortDeclTokens(delim) :: { [DeclToken] } : DeclTokensBase(PortDeclTokens(delim), delim) { $1 } | GenericInterfaceDecl PortDeclTokens(delim) { $1 ++ $2} - | GenericInterfaceDecl delim { $1 } + | GenericInterfaceDecl DTDelim(delim) { $1 ++ [$2] } | AttributeInstanceP PortDeclTokens(delim) { uncurry DTAttr $1 : $2 } ModuleDeclTokens(delim) :: { [DeclToken] } : DeclTokensBase(ModuleDeclTokens(delim), delim) { $1 } | GenericInterfaceDecl ModuleDeclTokens(delim) { $1 ++ $2} - | GenericInterfaceDecl delim { $1 } + | GenericInterfaceDecl DTDelim(delim) { $1 ++ [$2] } GenericInterfaceDecl :: { [DeclToken] } : "interface" IdentifierP { [DTType (tokenPosition $1) (\Unspecified -> InterfaceT "" ""), uncurry DTIdent $2] } diff --git a/src/Language/SystemVerilog/Parser/ParseDecl.hs b/src/Language/SystemVerilog/Parser/ParseDecl.hs index 8c8a784..d308284 100644 --- a/src/Language/SystemVerilog/Parser/ParseDecl.hs +++ b/src/Language/SystemVerilog/Parser/ParseDecl.hs @@ -45,7 +45,7 @@ module Language.SystemVerilog.Parser.ParseDecl , parseDTsAsDeclsOrAsgns ) where -import Data.List (findIndex, findIndices, partition, uncons) +import Data.List (findIndex, partition, uncons) import Language.SystemVerilog.AST import Language.SystemVerilog.Parser.Tokens (Position(..)) @@ -57,7 +57,7 @@ data DeclToken | DTConst Position | DTVar Position | DTAsgn Position AsgnOp (Maybe Timing) Expr - | DTRange Position (PartSelectMode, Range) + | DTRange Position PartSelectMode Range | DTIdent Position Identifier | DTPSIdent Position Identifier Identifier | DTCSIdent Position Identifier [ParamBinding] Identifier @@ -73,59 +73,34 @@ data DeclToken | DTSigning Position Signing | DTLifetime Position Lifetime | DTAttr Position Attr - deriving (Show, 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 + | DTEnd Position Char + deriving Eq -- [PUBLIC]: parser for module port declarations, including interface ports -- Example: `input foo, bar, One inst` parseDTsAsPortDecls :: [DeclToken] -> ([Identifier], [ModuleItem]) -parseDTsAsPortDecls pieces = - parseDTsAsPortDecls' $ - case last pieces of - DTComma{} -> init pieces - _ -> pieces +parseDTsAsPortDecls = parseDTsAsPortDecls' . dropTrailingComma + where + dropTrailingComma :: [DeclToken] -> [DeclToken] + dropTrailingComma [] = [] + dropTrailingComma [DTComma{}, end @ DTEnd{}] = [end] + dropTrailingComma (tok : toks) = tok : dropTrailingComma toks -- internal parseDTsAsPortDecls after the removal of an optional trailing comma parseDTsAsPortDecls' :: [DeclToken] -> ([Identifier], [ModuleItem]) parseDTsAsPortDecls' pieces = - forbidNonEqAsgn pieces `seq` if isSimpleList then (simpleIdents, []) else (portNames declarations, applyAttrs [] pieces declarations) 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 + maybeSimpleIdents = parseDTsAsIdents pieces + Just simpleIdents = maybeSimpleIdents + isSimpleList = maybeSimpleIdents /= Nothing - simpleIdents = map extractIdent $ filter isIdent pieces declarations = propagateDirections Input $ parseDTsAsDecls pieces' - extractIdent = \(DTIdent _ x) -> x - - pieces' = filter (not . isDTAttr) pieces - isDTAttr :: DeclToken -> Bool - isDTAttr DTAttr{} = True - isDTAttr _ = False + pieces' = filter (not . isAttr) pieces propagateDirections :: Direction -> [Decl] -> [Decl] propagateDirections dir (decl @ (Variable _ InterfaceT{} _ _ _) : decls) = @@ -149,12 +124,9 @@ parseDTsAsPortDecls' pieces = portName :: Decl -> Identifier portName (Variable _ _ ident _ _) = ident portName (Net _ _ _ _ ident _ _) = ident - portName CommentDecl{} = "" - portName decl = - error $ "unexpected non-variable port declaration: " ++ (show decl) + portName _ = "" applyAttrs :: [Attr] -> [DeclToken] -> [Decl] -> [ModuleItem] - applyAttrs _ [] [] = [] applyAttrs _ tokens (CommentDecl c : decls) = MIPackageItem (Decl $ CommentDecl c) : applyAttrs [] tokens decls applyAttrs attrs (DTAttr _ attr : tokens) decls = @@ -165,41 +137,53 @@ parseDTsAsPortDecls' pieces = wrapDecl attrs decl : 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 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 -- parameters) and module instantiations parseDTsAsModuleItems :: [DeclToken] -> [ModuleItem] parseDTsAsModuleItems tokens = - forbidNonEqAsgn tokens `seq` - if isElabTask $ head tokens then - asElabTask tokens + if maybeElabTask /= Nothing then + [elabTask] else if any isPorts tokens then parseDTsAsIntantiations tokens else map (MIPackageItem . Decl) $ parseDTsAsDecl tokens where - isElabTask :: DeclToken -> Bool - isElabTask (DTIdent _ x) = elem x elabTasks - where elabTasks = ["$fatal", "$error", "$warning", "$info"] - isElabTask _ = False + Just elabTask = maybeElabTask + maybeElabTask = asElabTask tokens --- internal; approximates the behavior of the elaboration system tasks -asElabTask :: [DeclToken] -> [ModuleItem] -asElabTask [DTIdent _ name, DTPorts _ args] = - if name == "$info" - then [] -- just drop them for simplicity - else [Instance "ThisModuleDoesNotExist" [] name' [] args] - where name' = "__sv2v_elab_" ++ tail name -asElabTask [DTIdent pos name] = - asElabTask [DTIdent pos name, DTPorts pos []] -asElabTask tokens = - error $ "could not parse elaboration system task: " ++ show tokens +-- internal; attempt to parse an elaboration system task +asElabTask :: [DeclToken] -> Maybe ModuleItem +asElabTask tokens = do + DTIdent _ x @ ('$' : _) <- return $ head tokens + severity <- lookup x elabTasks + Just $ ElabTask severity args + where + args = + case tail tokens of + [DTEnd{}] -> Args [] [] + [DTPorts _ ports, DTEnd{}] -> portsToArgs ports + DTPorts{} : tok : _ -> parseError tok msg + 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 parseDTsAsIntantiations :: [DeclToken] -> [ModuleItem] @@ -207,18 +191,12 @@ parseDTsAsIntantiations (DTIdent _ name : DTParams _ params : tokens) = step tokens where step :: [DeclToken] -> [ModuleItem] - step [] = parseError endTok "unexpected end of instantiation list" - step toks = inst : rest + step [] = [] + step toks = inst : step restToks where - (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 + (instToks, delimTok : restToks) = break isCommaOrEnd toks parseDTsAsIntantiations (DTIdent pos name : tokens) = parseDTsAsIntantiations $ DTIdent pos name : DTParams pos [] : tokens parseDTsAsIntantiations tokens = @@ -230,16 +208,20 @@ parseDTsAsIntantiation :: [DeclToken] -> DeclToken -> (Identifier, [Range], [PortBinding]) parseDTsAsIntantiation l0 delimTok = if null l0 then - parseError delimTok "expected instantiation before delimiter" + parseError delimTok $ "expected instantiation before " ++ delimStr else if not (isIdent nameTok) then parseError nameTok "expected instantiation name" 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 parseError portsTok "expected port connections" else (name, ranges, ports) where + delimChar = case delimTok of + DTEnd _ char -> char + _ -> ',' + delimStr = ['\'', delimChar, '\''] Just (nameTok, l1) = uncons l0 rangeToks = init l1 portsTok = last l1 @@ -247,7 +229,7 @@ parseDTsAsIntantiation l0 delimTok = DTPorts _ ports = portsTok ranges = map asRange rangeToks asRange :: DeclToken -> Range - asRange (DTRange _ (NonIndexed, s)) = s + asRange (DTRange _ NonIndexed s) = s asRange (DTBit _ s) = (RawNum 0, BinOp Sub s (RawNum 1)) asRange tok = parseError tok "expected instantiation dimensions" @@ -255,61 +237,61 @@ parseDTsAsIntantiation l0 delimTok = -- [PUBLIC]: parser for generic, comma-separated declarations parseDTsAsDecls :: [DeclToken] -> [Decl] parseDTsAsDecls tokens = - forbidNonEqAsgn tokens `seq` - concat $ map finalize $ parseDTsAsComponents tokens + concatMap finalize $ parseDTsAsComponents tokens -- internal; used for "single" declarations, i.e., declarations appearing -- outside of a port list parseDTsAsDecl :: [DeclToken] -> [Decl] parseDTsAsDecl tokens = - if length components /= 1 - then parseError tok $ "unexpected comma-separated declarations" - else finalize $ head components - where - components = parseDTsAsComponents tokens - _ : (pos, _, _) : _ = components - tok = DTComma pos + if null rest + then finalize component + else parseError (head rest) "unexpected token in declaration" + where (component, rest) = parseDTsAsComponent tokens -- [PUBLIC]: parser for single block item declarations or assign or arg-less -- subroutine call statements parseDTsAsDeclOrStmt :: [DeclToken] -> ([Decl], [Stmt]) -parseDTsAsDeclOrStmt (DTAsgn pos (AsgnOp op) mt e : tok : toks) = - parseDTsAsDeclOrStmt $ (tok : toks) ++ [DTAsgn pos (AsgnOp op) mt e] parseDTsAsDeclOrStmt tokens = - if not hasLeadingDecl - then ([], [traceStmt pos, stmt]) - else (parseDTsAsDecl tokens, []) + if declLookahead tokens + then (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 - pos = tokPos $ last tokens - 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 + (_, l1) = takeDir l0 (_, l2) = takeLifetime l1 (_, l3) = takeVarOrNet l2 (_, l4) = takeType l3 (_, l5) = takeRanges l4 -traceStmt :: Position -> Stmt -traceStmt pos = CommentStmt $ "Trace: " ++ show pos +-- internal; parser for leading statements in a procedural block +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 -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 +takeExpr :: [DeclToken] -> (Expr, [DeclToken]) +takeExpr (DTPSIdent _ p x : toks) = (PSIdent p x, toks) +takeExpr (DTCSIdent _ c p x : toks) = (CSIdent c p x, toks) +takeExpr toks = (lhsToExpr lhs, rest) + where (lhs, rest) = takeLHS toks -- converts port bindings to call args portsToArgs :: [PortBinding] -> Args @@ -324,66 +306,68 @@ portsToArgs bindings = -- is only used for `for` loop initialization lists parseDTsAsDeclsOrAsgns :: [DeclToken] -> Either [Decl] [(LHS, Expr)] parseDTsAsDeclsOrAsgns tokens = - forbidNonEqAsgn tokens `seq` - if hasLeadingAsgn || tripLookahead tokens - then Right $ parseDTsAsAsgns tokens - else Left $ map checkDecl $ parseDTsAsDecls tokens + if declLookahead tokens + then Left decls + else Right asgns where - hasLeadingAsgn = - -- if there is an asgn token before the next comma - case (findIndex isComma tokens, findIndex isAsgnToken tokens) of - (Just a, Just b) -> a > b - (Nothing, Just _) -> True - _ -> False - checkDecl :: Decl -> Decl - checkDecl (decl @ (Variable _ _ _ _ Nil)) = - error $ "for loop declaration missing initialization: " - ++ init (show decl) - checkDecl decl = decl + decls = concatMap finalize components + components = map checkComponent $ parseDTsAsComponents tokens + asgns = parseDTsAsAsgns $ shiftIncOrDec tokens + checkComponent :: Component -> Component + checkComponent (pos, base, trips) = + (pos, base, map (checkTriplet pos) trips) + checkTriplet :: Position -> Triplet -> Triplet + checkTriplet pos (x, _, Nil) = + parseError pos $ "for loop declaration of " ++ show x + ++ " is missing initialization" + checkTriplet _ trip = trip -- internal parser for basic assignment lists parseDTsAsAsgns :: [DeclToken] -> [(LHS, Expr)] parseDTsAsAsgns tokens = - case l1 of - [] -> [asgn] - DTComma{} : remaining -> asgn : parseDTsAsAsgns remaining - _ -> error $ "bad assignment tokens: " ++ show tokens + if not (isAsgn asgnTok) then + parseError asgnTok "expected assignment operator" + else if mt /= Nothing then + unexpected "timing modifier" + else (lhs, expr) : case head remaining of + DTEnd{} -> [] + DTComma{} -> parseDTsAsAsgns $ tail remaining + tok -> parseError tok "expected ',' or ';'" where - (lhsToks, l0) = break isDTAsgn tokens - lhs = case takeLHS lhsToks of - Nothing -> error $ "could not parse as LHS: " ++ show lhsToks - Just l -> l - DTAsgn _ AsgnOpEq Nothing expr : l1 = l0 - asgn = (lhs, expr) + (lhs, asgnTok : remaining) = takeLHS tokens + DTAsgn _ op mt rhs = asgnTok + expr = case op of + AsgnOpEq -> rhs + AsgnOpNonBlocking -> unexpected "non-blocking assignment" + AsgnOp binop -> BinOp binop (lhsToExpr lhs) rhs - isDTAsgn :: DeclToken -> Bool - isDTAsgn (DTAsgn _ _ Nothing _) = True - isDTAsgn _ = False + unexpected surprise = parseError asgnTok $ + "unexpected " ++ surprise ++ " in for loop initialization" -isAsgnToken :: DeclToken -> Bool -isAsgnToken (DTBit{} ) = True -isAsgnToken (DTConcat{}) = True -isAsgnToken (DTStream{}) = True -isAsgnToken (DTDot{} ) = True -isAsgnToken (DTAsgn _ op _ _) = op /= AsgnOpEq -isAsgnToken _ = False +shiftIncOrDec :: [DeclToken] -> [DeclToken] +shiftIncOrDec (tok @ (DTAsgn _ AsgnOp{} _ _) : toks) = + before ++ tok : delim : shiftIncOrDec after + where (before, delim : after) = break isCommaOrEnd toks +shiftIncOrDec [] = [] +shiftIncOrDec toks = + before ++ delim : shiftIncOrDec after + where (before, delim : after) = break isCommaOrEnd toks -takeLHS :: [DeclToken] -> Maybe LHS -takeLHS [] = Nothing -takeLHS (t : ts) = - foldl takeLHSStep (takeLHSStart t) ts +takeLHS :: [DeclToken] -> (LHS, [DeclToken]) +takeLHS tokens = takeLHSStep (takeLHSStart tok) toks + where tok : toks = tokens -takeLHSStart :: DeclToken -> Maybe LHS -takeLHSStart (DTConcat _ lhss) = Just $ LHSConcat lhss -takeLHSStart (DTStream _ o e lhss) = Just $ LHSStream o e lhss -takeLHSStart (DTIdent _ x ) = Just $ LHSIdent x -takeLHSStart _ = Nothing +takeLHSStart :: DeclToken -> LHS +takeLHSStart (DTConcat _ lhss) = LHSConcat lhss +takeLHSStart (DTStream _ o e lhss) = LHSStream o e lhss +takeLHSStart (DTIdent _ x ) = LHSIdent x +takeLHSStart tok = parseError tok "expected primary token or type" -takeLHSStep :: Maybe LHS -> DeclToken -> Maybe LHS -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 -takeLHSStep _ _ = Nothing +takeLHSStep :: LHS -> [DeclToken] -> (LHS, [DeclToken]) +takeLHSStep curr (DTBit _ e : toks) = takeLHSStep (LHSBit curr e ) toks +takeLHSStep curr (DTRange _ m r : toks) = takeLHSStep (LHSRange curr m r) toks +takeLHSStep curr (DTDot _ x : toks) = takeLHSStep (LHSDot curr x ) toks +takeLHSStep lhs toks = (lhs, toks) -- batches together separate declaration lists @@ -404,13 +388,11 @@ parseDTsAsComponents tokens = where (component, tokens') = parseDTsAsComponent tokens parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken]) -parseDTsAsComponent [] = error "parseDTsAsComponent unexpected end of tokens" parseDTsAsComponent l0 = 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 - error $ "declaration(s) missing type information: " - ++ show (position, tps) + parseError (head l0) "declaration missing type information" else (component, l6) where @@ -419,50 +401,37 @@ parseDTsAsComponent l0 = (von, l3) = takeVarOrNet l2 (tf , l4) = takeType l3 (rs , l5) = takeRanges l4 - (tps, l6) = takeTrips l5 True + (tps, l6) = takeTrips l5 position = tokPos $ head l0 base = von dir $ tf rs component = (position, base, 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) +takeTrips :: [DeclToken] -> ([Triplet], [DeclToken]) +takeTrips l0 = + (trip : trips, l5) where (x, l1) = takeIdent l0 (a, l2) = takeRanges l1 (e, l3) = takeAsgn l2 - (_, l4) = takeComma l3 + l4 = takeCommaOrEnd l3 trip = (x, a, e) - (trips, l5) = takeTrips l4 False + (trips, l5) = + if tripLookahead l4 + then takeTrips l4 + else ([], l4) tripLookahead :: [DeclToken] -> Bool -tripLookahead [] = False tripLookahead l0 = + not (null 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 /= 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) + isIdent (head l0) && + -- expecting to see a comma or the ending token after the identifier and + -- optional ranges and/or assignment + isCommaOrEnd (head l3) where - (_ , l1) = takeIdent l0 - (_ , l2) = takeRanges l1 - (asgn, l3) = takeAsgn l2 + (_, l1) = takeIdent l0 + (_, l2) = takeRanges l1 + (_, l3) = takeAsgn l2 takeDir :: [DeclToken] -> (Direction, [DeclToken]) takeDir (DTDir _ dir : rest) = (dir , rest) @@ -473,8 +442,8 @@ takeLifetime (DTLifetime _ l : rest) = (Just l, rest) takeLifetime rest = (Nothing, rest) takeVarOrNet :: [DeclToken] -> (Direction -> Type -> DeclBase, [DeclToken]) -takeVarOrNet (DTConst{} : tok @ DTConst{} : _) = - parseError tok "duplicate const modifier" +takeVarOrNet (DTConst{} : DTConst pos : _) = + parseError pos "duplicate const modifier" takeVarOrNet (DTConst _ : tokens) = takeVarOrNet tokens takeVarOrNet (DTNet _ n s : tokens) = (\d -> Net d n s, tokens) takeVarOrNet tokens = (Variable, tokens) @@ -499,8 +468,8 @@ takeType (DTIdent pos tn : rest) = (_, Nothing) -> True -- if comma is first, then this ident is a declaration (Just a, Just b) -> a < b -takeType (DTVar{} : tok @ DTVar{} : _) = - parseError tok "duplicate var modifier" +takeType (DTVar{} : DTVar pos : _) = + parseError pos "duplicate var modifier" takeType (DTVar _ : rest) = case tf [] of Implicit sg [] -> (IntegerVector TLogic sg, rest') @@ -509,19 +478,18 @@ takeType (DTVar _ : rest) = takeType rest = (Implicit Unspecified, rest) takeRanges :: [DeclToken] -> ([Range], [DeclToken]) -takeRanges [] = ([], []) -takeRanges (token : tokens) = - case token of - DTRange _ (NonIndexed, r) -> (r : rs, rest ) - DTBit _ s -> (asRange s : rs, rest ) - DTAutoDim _ -> - case rest of - (DTAsgn _ AsgnOpEq Nothing (Pattern l) : _) -> autoDim l - (DTAsgn _ AsgnOpEq Nothing (Concat l) : _) -> autoDim l - _ -> ([] , token : tokens) - _ -> ([] , token : tokens) +takeRanges tokens = + case head tokens of + DTRange _ NonIndexed r -> (r : rs, rest) + DTBit _ s -> (asRange s : rs, rest) + DTAutoDim _ -> + case head $ tail tokens of + DTAsgn _ AsgnOpEq Nothing (Pattern l) -> autoDim l + DTAsgn _ AsgnOpEq Nothing (Concat l) -> autoDim l + _ -> ([], tokens) + _ -> ([], tokens) where - (rs, rest) = takeRanges tokens + (rs, rest) = takeRanges $ tail tokens asRange s = (RawNum 0, BinOp Sub s (RawNum 1)) autoDim :: [a] -> ([Range], [DeclToken]) autoDim l = @@ -531,35 +499,53 @@ takeRanges (token : tokens) = lo = RawNum 0 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 (DTAsgn _ op Nothing e : rest) = - if op == AsgnOpEq || op == AsgnOpNonBlocking - then (e , rest) - else (Nil, rest) +takeAsgn (tok @ (DTAsgn _ op mt e) : rest) = + if op == AsgnOpNonBlocking then + unexpected "non-blocking assignment operator" + 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) -takeComma :: [DeclToken] -> (Bool, [DeclToken]) -takeComma [] = (False, []) -takeComma (DTComma{} : rest) = (True, rest) -takeComma toks = error $ "expected comma or end of decl, got: " ++ show toks +takeCommaOrEnd :: [DeclToken] -> [DeclToken] +takeCommaOrEnd tokens = + if isCommaOrEnd tok + then toks + else parseError tok "expected comma or end of declarations" + where tok : toks = tokens takeIdent :: [DeclToken] -> (Identifier, [DeclToken]) 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 (DTIdent{}) = True +isIdent DTIdent{} = True isIdent _ = False isComma :: DeclToken -> Bool -isComma (DTComma{}) = True +isComma DTComma{} = True isComma _ = False +isCommaOrEnd :: DeclToken -> Bool +isCommaOrEnd DTEnd{} = True +isCommaOrEnd tok = isComma tok + isPorts :: DeclToken -> Bool isPorts DTPorts{} = True isPorts _ = False @@ -570,7 +556,7 @@ tokPos (DTAutoDim p) = p tokPos (DTConst p) = p tokPos (DTVar p) = p tokPos (DTAsgn p _ _ _) = p -tokPos (DTRange p _) = p +tokPos (DTRange p _ _) = p tokPos (DTIdent p _) = p tokPos (DTPSIdent p _ _) = p tokPos (DTCSIdent p _ _ _) = p @@ -586,7 +572,13 @@ tokPos (DTDot p _) = p tokPos (DTSigning p _) = p tokPos (DTLifetime p _) = p tokPos (DTAttr p _) = p +tokPos (DTEnd p _) = p -parseError :: DeclToken -> String -> a -parseError tok msg = error $ show pos ++ ": Parse error: " ++ msg - where pos = tokPos tok +class Loc t where + parseError :: t -> String -> a + +instance Loc Position where + parseError pos msg = error $ show pos ++ ": Parse error: " ++ msg + +instance Loc DeclToken where + parseError = parseError . tokPos diff --git a/test/core/elab_task.sv b/test/core/elab_task.sv deleted file mode 100644 index 381a427..0000000 --- a/test/core/elab_task.sv +++ /dev/null @@ -1,6 +0,0 @@ -module top; - if (1 == 0) - wire foo; - else - $info("foo"); -endmodule diff --git a/test/core/elab_task.v b/test/core/elab_task.v deleted file mode 100644 index 4a271fc..0000000 --- a/test/core/elab_task.v +++ /dev/null @@ -1,2 +0,0 @@ -module top; -endmodule diff --git a/test/core/for_loop_inits.sv b/test/core/for_loop_inits.sv new file mode 100644 index 0000000..c62a193 --- /dev/null +++ b/test/core/for_loop_inits.sv @@ -0,0 +1,58 @@ +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 diff --git a/test/core/for_loop_inits.v b/test/core/for_loop_inits.v new file mode 100644 index 0000000..2293602 --- /dev/null +++ b/test/core/for_loop_inits.v @@ -0,0 +1,20 @@ +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 diff --git a/test/error/auto_dim_int.sv b/test/error/auto_dim_int.sv new file mode 100644 index 0000000..89062ad --- /dev/null +++ b/test/error/auto_dim_int.sv @@ -0,0 +1,4 @@ +// pattern: auto_dim_int\.sv:3:15: Parse error: expected comma or end of declarations +module top; + integer x [] = 1; +endmodule diff --git a/test/error/block_start_1.sv b/test/error/block_start_1.sv new file mode 100644 index 0000000..56cfdc2 --- /dev/null +++ b/test/error/block_start_1.sv @@ -0,0 +1,6 @@ +// pattern: block_start_1\.sv:4:9: Parse error: expected primary token or type +module top; + initial begin + ,; + end +endmodule diff --git a/test/error/block_start_2.sv b/test/error/block_start_2.sv new file mode 100644 index 0000000..f86870d --- /dev/null +++ b/test/error/block_start_2.sv @@ -0,0 +1,6 @@ +// pattern: block_start_2\.sv:4:9: Parse error: expected primary token or type +module top; + initial begin + = 1; + end +endmodule diff --git a/test/error/block_start_3.sv b/test/error/block_start_3.sv new file mode 100644 index 0000000..c5f43b9 --- /dev/null +++ b/test/error/block_start_3.sv @@ -0,0 +1,6 @@ +// pattern: block_start_3\.sv:4:9: Parse error: expected primary token or type +module top; + initial begin + P::Q = 1; + end +endmodule diff --git a/test/error/block_start_4.sv b/test/error/block_start_4.sv new file mode 100644 index 0000000..8e039f9 --- /dev/null +++ b/test/error/block_start_4.sv @@ -0,0 +1,6 @@ +// pattern: block_start_4\.sv:4:11: Parse error: unexpected statement token +module top; + initial begin + a , ; + end +endmodule diff --git a/test/error/decl_bare.sv b/test/error/decl_bare.sv new file mode 100644 index 0000000..c7bc60a --- /dev/null +++ b/test/error/decl_bare.sv @@ -0,0 +1,4 @@ +// pattern: decl_bare\.sv:3:5: Parse error: declaration missing type information +module top; + a; +endmodule diff --git a/test/error/decl_missing_comma.sv b/test/error/decl_missing_comma.sv new file mode 100644 index 0000000..42eed14 --- /dev/null +++ b/test/error/decl_missing_comma.sv @@ -0,0 +1,4 @@ +// pattern: decl_missing_comma\.sv:3:15: Parse error: expected comma or end of declarations +module top; + integer a b; +endmodule diff --git a/test/error/decl_trailing_comma.sv b/test/error/decl_trailing_comma.sv new file mode 100644 index 0000000..6d76d02 --- /dev/null +++ b/test/error/decl_trailing_comma.sv @@ -0,0 +1,4 @@ +// pattern: decl_trailing_comma\.sv:3:16: Parse error: unexpected token in declaration +module top; + integer a, ; +endmodule diff --git a/test/error/elab_task_stray_after_args.sv b/test/error/elab_task_stray_after_args.sv new file mode 100644 index 0000000..f85f919 --- /dev/null +++ b/test/error/elab_task_stray_after_args.sv @@ -0,0 +1,4 @@ +// pattern: elab_task_stray_after_args\.sv:3:12: Parse error: unexpected token after elaboration system task +module top; + $info(), ; +endmodule diff --git a/test/error/elab_task_stray_before_args.sv b/test/error/elab_task_stray_before_args.sv new file mode 100644 index 0000000..fa68c86 --- /dev/null +++ b/test/error/elab_task_stray_before_args.sv @@ -0,0 +1,4 @@ +// pattern: elab_task_stray_before_args\.sv:3:11: Parse error: unexpected token after elaboration system task +module top; + $info , (); +endmodule diff --git a/test/error/elab_task_stray_no_args.sv b/test/error/elab_task_stray_no_args.sv new file mode 100644 index 0000000..2054dbb --- /dev/null +++ b/test/error/elab_task_stray_no_args.sv @@ -0,0 +1,4 @@ +// pattern: elab_task_stray_no_args\.sv:3:11: Parse error: unexpected token after elaboration system task +module top; + $info , ; +endmodule diff --git a/test/error/for_loop_decl_no_init.sv b/test/error/for_loop_decl_no_init.sv index 7478f6a..c5d0c65 100644 --- a/test/error/for_loop_decl_no_init.sv +++ b/test/error/for_loop_decl_no_init.sv @@ -1,4 +1,4 @@ -// 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; initial for (integer x; x < 3; x = x + 1) diff --git a/test/error/for_loop_init_bare.sv b/test/error/for_loop_init_bare.sv new file mode 100644 index 0000000..e628b16 --- /dev/null +++ b/test/error/for_loop_init_bare.sv @@ -0,0 +1,4 @@ +// pattern: for_loop_init_bare\.sv:3:19: Parse error: expected assignment operator +module top; + initial for (a,; 1; a++) ; +endmodule diff --git a/test/error/for_loop_init_delay.sv b/test/error/for_loop_init_delay.sv new file mode 100644 index 0000000..bcd318d --- /dev/null +++ b/test/error/for_loop_init_delay.sv @@ -0,0 +1,5 @@ +// 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 diff --git a/test/error/for_loop_init_nblk.sv b/test/error/for_loop_init_nblk.sv new file mode 100644 index 0000000..0db74a7 --- /dev/null +++ b/test/error/for_loop_init_nblk.sv @@ -0,0 +1,5 @@ +// 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 diff --git a/test/error/for_loop_init_stray.sv b/test/error/for_loop_init_stray.sv new file mode 100644 index 0000000..f86046b --- /dev/null +++ b/test/error/for_loop_init_stray.sv @@ -0,0 +1,4 @@ +// pattern: for_loop_init_stray\.sv:3:22: Parse error: expected ',' or ';' +module top; + initial for (a++ b++; 1; a++) ; +endmodule diff --git a/test/error/instantiation_extra_comma.sv b/test/error/instantiation_extra_comma.sv index 112a4e0..0541703 100644 --- a/test/error/instantiation_extra_comma.sv +++ b/test/error/instantiation_extra_comma.sv @@ -1,4 +1,4 @@ -// 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; example a(), , b(); endmodule diff --git a/test/error/instantiation_missing_ports.sv b/test/error/instantiation_missing_ports.sv index f8aa081..f5a9c75 100644 --- a/test/error/instantiation_missing_ports.sv +++ b/test/error/instantiation_missing_ports.sv @@ -1,4 +1,4 @@ -// 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; example a, c(); endmodule diff --git a/test/error/instantiation_trailing_comma.sv b/test/error/instantiation_trailing_comma.sv index 257065a..6d3c2e9 100644 --- a/test/error/instantiation_trailing_comma.sv +++ b/test/error/instantiation_trailing_comma.sv @@ -1,4 +1,4 @@ -// 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; example a(), ; endmodule diff --git a/test/error/port_list_incomplete.sv b/test/error/port_list_incomplete.sv new file mode 100644 index 0000000..edd00e6 --- /dev/null +++ b/test/error/port_list_incomplete.sv @@ -0,0 +1,3 @@ +// pattern: port_list_incomplete\.sv:2:17: Parse error: expected identifier +module top(input); +endmodule diff --git a/test/error/run_on_decl_item.sv b/test/error/run_on_decl_item.sv index b223e0d..e849bc9 100644 --- a/test/error/run_on_decl_item.sv +++ b/test/error/run_on_decl_item.sv @@ -1,4 +1,4 @@ -// 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; integer x, byte y; endmodule diff --git a/test/error/run_on_decl_stmt.sv b/test/error/run_on_decl_stmt.sv index 073bade..2c90f02 100644 --- a/test/error/run_on_decl_stmt.sv +++ b/test/error/run_on_decl_stmt.sv @@ -1,4 +1,4 @@ -// 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; initial begin integer x, byte y; diff --git a/test/nosim/elab_task.sv b/test/nosim/elab_task.sv new file mode 100644 index 0000000..87e14bb --- /dev/null +++ b/test/nosim/elab_task.sv @@ -0,0 +1,10 @@ +module top; + $info; + $info("%b", 1); + $warning; + $warning("%b", 2); + $error; + $error("%b", 3); + $fatal; + $fatal("%b", 4); +endmodule diff --git a/test/nosim/run.sh b/test/nosim/run.sh new file mode 100755 index 0000000..0f01aed --- /dev/null +++ b/test/nosim/run.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +addTest() { + test=$1 + eval "test_$test() { assertConverts $test.sv; }" + suite_addTest test_$test +} + +source ../lib/functions.sh +source ../lib/discover.sh + +. shunit2 diff --git a/test/nosim/trireg_charge_strength.sv b/test/nosim/trireg_charge_strength.sv new file mode 100644 index 0000000..3cbc22b --- /dev/null +++ b/test/nosim/trireg_charge_strength.sv @@ -0,0 +1,5 @@ +module top; + trireg (small) x; + trireg (medium) y; + trireg (large) z; +endmodule