diff --git a/src/Language/SystemVerilog/Parser/Parse.y b/src/Language/SystemVerilog/Parser/Parse.y index 60fa289..63a1616 100644 --- a/src/Language/SystemVerilog/Parser/Parse.y +++ b/src/Language/SystemVerilog/Parser/Parse.y @@ -874,7 +874,7 @@ ClassItemQualifier :: { Qualifier } | "protected" { QProtected } PackageOrClassItem :: { [PackageItem] } - : DeclTokens(";") { map Decl $ parseDTsAsDecls $1 } + : DeclTokens(";") { map Decl $ parseDTsAsDecl $1 } | ParameterDecl(";") { map Decl $1 } | NonDeclPackageItem { $1 } NonDeclPackageItem :: { [PackageItem] } @@ -951,7 +951,7 @@ ExplicitLifetime :: { Lifetime } | "automatic" { Automatic } TFItems :: { [Decl] } - : "(" DeclTokens(")") ";" { parseDTsAsDecls $2 } + : "(" DeclTokens(")") ";" { parseDTsAsTFDecls $2 } | "(" ")" ";" { [] } | ";" { [] } diff --git a/src/Language/SystemVerilog/Parser/ParseDecl.hs b/src/Language/SystemVerilog/Parser/ParseDecl.hs index 88d2fa2..04e489c 100644 --- a/src/Language/SystemVerilog/Parser/ParseDecl.hs +++ b/src/Language/SystemVerilog/Parser/ParseDecl.hs @@ -39,7 +39,8 @@ module Language.SystemVerilog.Parser.ParseDecl ( DeclToken (..) , parseDTsAsPortDecls , parseDTsAsModuleItems -, parseDTsAsDecls +, parseDTsAsTFDecls +, parseDTsAsDecl , parseDTsAsDeclOrStmt , parseDTsAsDeclsOrAsgns ) where @@ -95,7 +96,8 @@ parseDTsAsPortDecls' pieces = Just simpleIdents = maybeSimpleIdents isSimpleList = maybeSimpleIdents /= Nothing - declarations = propagateDirections Input $ parseDTsAsDecls pieces' + declarations = propagateDirections Input $ + parseDTsAsDecls ModeDefault pieces' pieces' = filter (not . isAttr) pieces @@ -231,20 +233,15 @@ parseDTsAsIntantiation l0 delimTok = asRange tok = parseError tok "expected instantiation dimensions" --- [PUBLIC]: parser for generic, comma-separated declarations -parseDTsAsDecls :: [DeclToken] -> [Decl] -parseDTsAsDecls tokens = - concatMap finalize $ parseDTsAsComponents tokens +-- [PUBLIC]: parser for comma-separated task/function port declarations +parseDTsAsTFDecls :: [DeclToken] -> [Decl] +parseDTsAsTFDecls = parseDTsAsDecls ModeDefault --- internal; used for "single" declarations, i.e., declarations appearing +-- [PUBLIC]; used for "single" declarations, i.e., declarations appearing -- outside of a port list parseDTsAsDecl :: [DeclToken] -> [Decl] -parseDTsAsDecl tokens = - if null rest - then finalize component - else parseError (head rest) "unexpected token in declaration" - where (component, rest) = parseDTsAsComponent tokens +parseDTsAsDecl = parseDTsAsDecls ModeSingle -- [PUBLIC]: parser for single block item declarations or assign or arg-less @@ -305,20 +302,8 @@ portsToArgs bindings = parseDTsAsDeclsOrAsgns :: [DeclToken] -> Either [Decl] [(LHS, Expr)] parseDTsAsDeclsOrAsgns tokens = if declLookahead tokens - then Left decls - else Right asgns - where - 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 + then Left $ parseDTsAsDecls ModeForLoop tokens + else Right $ parseDTsAsAsgns $ shiftIncOrDec tokens -- internal parser for basic assignment lists parseDTsAsAsgns :: [DeclToken] -> [(LHS, Expr)] @@ -367,60 +352,68 @@ takeLHSStep curr (DTDot _ x : toks) = takeLHSStep (LHSDot curr x ) toks takeLHSStep lhs toks = (lhs, toks) --- batches together separate declaration lists type DeclBase = Identifier -> [Range] -> Expr -> Decl type Triplet = (Identifier, [Range], Expr) -type Component = (Position, DeclBase, [Triplet]) -finalize :: Component -> [Decl] -finalize (pos, base, trips) = - CommentDecl ("Trace: " ++ show pos) : - map (\(x, a, e) -> base x a e) trips +data Mode + = ModeForLoop -- initialization always required + | ModeSingle -- single declaration (not port list) + | ModeDefault -- comma separated, multiple declarations + deriving Eq -- internal; entrypoint of the critical portion of our parser -parseDTsAsComponents :: [DeclToken] -> [Component] -parseDTsAsComponents [] = [] -parseDTsAsComponents tokens = - component : parseDTsAsComponents tokens' - where (component, tokens') = parseDTsAsComponent tokens - -parseDTsAsComponent :: [DeclToken] -> (Component, [DeclToken]) -parseDTsAsComponent l0 = +parseDTsAsDecls :: Mode -> [DeclToken] -> [Decl] +parseDTsAsDecls mode l0 = if l /= Nothing && l /= Just Automatic then parseError (head l1) "unexpected non-automatic lifetime" else if dir == Local && isImplicit t && not (isNet $ head l3) then parseError (head l0) "declaration missing type information" + else if null l7 then + decls + else if mode == ModeSingle then + parseError (head l7) "unexpected token in declaration" else - (component, l7) + decls ++ parseDTsAsDecls mode l7 where + initReason + | hasDriveStrength (head l3) = "net with drive strength" + | mode == ModeForLoop = "for loop" + | con = "const" + | otherwise = "" (dir, l1) = takeDir l0 (l , l2) = takeLifetime l1 - (_ct, l3) = takeConst l2 + (con, l3) = takeConst l2 (von, l4) = takeVarOrNet l3 (tf , l5) = takeType l4 (rs , l6) = takeRanges l5 - (tps, l7) = takeTrips l6 - position = tokPos $ head l0 + (tps, l7) = takeTrips l6 initReason + pos = tokPos $ head l0 base = von dir t t = tf rs - component = (position, base, tps) + decls = + CommentDecl ("Trace: " ++ show pos) : + map (\(x, a, e) -> base x a e) tps + +hasDriveStrength :: DeclToken -> Bool +hasDriveStrength (DTNet _ _ DriveStrength{}) = True +hasDriveStrength _ = False isImplicit :: Type -> Bool isImplicit Implicit{} = True isImplicit _ = False -takeTrips :: [DeclToken] -> ([Triplet], [DeclToken]) -takeTrips l0 = +takeTrips :: [DeclToken] -> String -> ([Triplet], [DeclToken]) +takeTrips l0 initReason = (trip : trips, l5) where (x, l1) = takeIdent l0 (a, l2) = takeRanges l1 - (e, l3) = takeAsgn l2 + (e, l3) = takeAsgn l2 initReason l4 = takeCommaOrEnd l3 trip = (x, a, e) (trips, l5) = if tripLookahead l4 - then takeTrips l4 + then takeTrips l4 initReason else ([], l4) tripLookahead :: [DeclToken] -> Bool @@ -434,7 +427,7 @@ tripLookahead l0 = where (_, l1) = takeIdent l0 (_, l2) = takeRanges l1 - (_, l3) = takeAsgn l2 + (_, l3) = takeAsgn l2 "" takeDir :: [DeclToken] -> (Direction, [DeclToken]) takeDir (DTDir _ dir : rest) = (dir , rest) @@ -447,13 +440,22 @@ takeLifetime rest = (Nothing, rest) takeConst :: [DeclToken] -> (Bool, [DeclToken]) takeConst (DTConst{} : DTConst pos : _) = parseError pos "duplicate const modifier" +takeConst (DTConst pos : DTNet _ typ _ : _) = + parseError pos $ show typ ++ " cannot be const" takeConst (DTConst{} : tokens) = (True, tokens) takeConst tokens = (False, tokens) takeVarOrNet :: [DeclToken] -> (Direction -> Type -> DeclBase, [DeclToken]) takeVarOrNet (DTNet{} : DTVar pos : _) = parseError pos "unexpected var after net type" -takeVarOrNet (DTNet _ n s : tokens) = (\d -> Net d n s, tokens) +takeVarOrNet (DTNet pos n s : tokens) = + if n /= TTrireg && isChargeStrength s + then parseError pos "only trireg can have a charge strength" + else (\d -> Net d n s, tokens) + where + isChargeStrength :: Strength -> Bool + isChargeStrength ChargeStrength{} = True + isChargeStrength _ = False takeVarOrNet tokens = (Variable, tokens) takeType :: [DeclToken] -> ([Range] -> Type, [DeclToken]) @@ -507,8 +509,8 @@ takeRanges tokens = lo = RawNum 0 hi = RawNum $ fromIntegral $ n - 1 -takeAsgn :: [DeclToken] -> (Expr, [DeclToken]) -takeAsgn (tok @ (DTAsgn _ op mt e) : rest) = +takeAsgn :: [DeclToken] -> String -> (Expr, [DeclToken]) +takeAsgn (DTAsgn pos op mt e : rest) _ = if op == AsgnOpNonBlocking then unexpected "non-blocking assignment operator" else if op /= AsgnOpEq then @@ -519,8 +521,11 @@ takeAsgn (tok @ (DTAsgn _ op mt e) : rest) = (e, rest) where unexpected surprise = - parseError tok $ "unexpected " ++ surprise ++ " in declaration" -takeAsgn rest = (Nil, rest) + parseError pos $ "unexpected " ++ surprise ++ " in declaration" +takeAsgn rest "" = (Nil, rest) +takeAsgn toks initReason = + parseError (head toks) $ + initReason ++ " declaration is missing initialization" takeCommaOrEnd :: [DeclToken] -> [DeclToken] takeCommaOrEnd tokens = diff --git a/test/error/charge_strength_non_trireg.sv b/test/error/charge_strength_non_trireg.sv new file mode 100644 index 0000000..9e93410 --- /dev/null +++ b/test/error/charge_strength_non_trireg.sv @@ -0,0 +1,4 @@ +// pattern: charge_strength_non_trireg\.sv:3:5: Parse error: only trireg can have a charge strength +module top; + wire (small) x; +endmodule diff --git a/test/error/decl_const_var_uninit.sv b/test/error/decl_const_var_uninit.sv new file mode 100644 index 0000000..6d5dc88 --- /dev/null +++ b/test/error/decl_const_var_uninit.sv @@ -0,0 +1,4 @@ +// pattern: decl_const_var_uninit\.sv:3:16: Parse error: const declaration is missing initialization +module top; + const var x; +endmodule diff --git a/test/error/decl_const_wire.sv b/test/error/decl_const_wire.sv new file mode 100644 index 0000000..20be2a9 --- /dev/null +++ b/test/error/decl_const_wire.sv @@ -0,0 +1,4 @@ +// pattern: decl_const_wire\.sv:3:5: Parse error: wire cannot be const +module top; + const wire x = 1; +endmodule diff --git a/test/error/drive_strength_uninit.sv b/test/error/drive_strength_uninit.sv new file mode 100644 index 0000000..50b9316 --- /dev/null +++ b/test/error/drive_strength_uninit.sv @@ -0,0 +1,4 @@ +// pattern: drive_strength_uninit\.sv:3:30: Parse error: net with drive strength declaration is missing initialization +module top; + wire (supply0, supply1) x; +endmodule diff --git a/test/error/for_loop_decl_no_init.sv b/test/error/for_loop_decl_no_init.sv index c5d0c65..224e543 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_decl_no_init\.sv:4:14: Parse error: for loop declaration of "x" is missing initialization +// pattern: for_loop_decl_no_init\.sv:4:23: Parse error: for loop declaration is missing initialization module top; initial for (integer x; x < 3; x = x + 1) diff --git a/test/error/run_on_decl_package.sv b/test/error/run_on_decl_package.sv new file mode 100644 index 0000000..e024736 --- /dev/null +++ b/test/error/run_on_decl_package.sv @@ -0,0 +1,9 @@ +// pattern: run_on_decl_package\.sv:3:16: Parse error: unexpected token in declaration +package P; + integer x, byte y; + localparam Z = 1; +endpackage + +module top; + initial $display(P::Z); +endmodule