diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-10-19 01:05:10 -0600 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-10-19 01:05:10 -0600 |
commit | e9ed9fe9aae2c0ac913cf1d175166e983e0a1b30 (patch) | |
tree | 77ef1aaccd3527c06edff1c3120147150829bf3f | |
parent | e753d874458dce4ad480caba97fde8b73d703821 (diff) | |
download | fiddle-e9ed9fe9aae2c0ac913cf1d175166e983e0a1b30.tar.gz fiddle-e9ed9fe9aae2c0ac913cf1d175166e983e0a1b30.tar.bz2 fiddle-e9ed9fe9aae2c0ac913cf1d175166e983e0a1b30.zip |
Provide more data during qualification about how a path is qualified.
Now it includes information about the package a symobl is in. The object
its in and the register its in. This allows better code generation in
the backend that's somewhat more organized.
-rw-r--r-- | src/Language/Fiddle/Ast/Internal/SyntaxTree.hs | 8 | ||||
-rw-r--r-- | src/Language/Fiddle/Ast/Internal/Util.hs | 2 | ||||
-rw-r--r-- | src/Language/Fiddle/Compiler/Backend/C.hs | 104 | ||||
-rw-r--r-- | src/Language/Fiddle/Compiler/Backend/Internal.hs | 18 | ||||
-rw-r--r-- | src/Language/Fiddle/Compiler/ConsistencyCheck.hs | 3 | ||||
-rw-r--r-- | src/Language/Fiddle/Compiler/Qualification.hs | 170 | ||||
-rw-r--r-- | src/Language/Fiddle/GenericTree.hs | 2 | ||||
-rw-r--r-- | src/Language/Fiddle/Internal/UnitInterface.hs | 60 | ||||
-rw-r--r-- | src/Language/Fiddle/Parser.hs | 7 |
9 files changed, 276 insertions, 98 deletions
diff --git a/src/Language/Fiddle/Ast/Internal/SyntaxTree.hs b/src/Language/Fiddle/Ast/Internal/SyntaxTree.hs index 613dae4..063913b 100644 --- a/src/Language/Fiddle/Ast/Internal/SyntaxTree.hs +++ b/src/Language/Fiddle/Ast/Internal/SyntaxTree.hs @@ -96,7 +96,7 @@ data QRegMetadata (checkStage :: Bool) where -- emit getters and setters. regIsUnnamed :: Bool, -- | Full path to the register. - regFullPath :: NonEmpty String + regFullPath :: QualifiedPath String } -> QRegMetadata checkStage deriving (Generic, ToJSON) @@ -108,7 +108,7 @@ deriving instance data QBitsMetadata (checkStage :: Bool) where QBitsMetadata :: { bitsSpan :: When checkStage (FieldSpan Bits), - bitsFullPath :: NonEmpty String + bitsFullPath :: QualifiedPath String } -> QBitsMetadata checkStage deriving (Generic, ToJSON) @@ -619,7 +619,7 @@ data RegisterBitsDecl stage f a where qBitsMetadata :: When (stage .>= Qualified) (QBitsMetadata (stage .>= Checked)), -- | Bit declarations. -- | Optional modifier for the bits. - definedBitsModifier :: Maybe (Modifier f a), + definedBitsModifier :: Guaranteed (stage .>= Qualified) (Modifier f a), -- | Identifier for the bits. definedBitsIdent :: Identifier f a, -- | Type reference for the bits. @@ -676,7 +676,7 @@ data RegisterBitsTypeRef stage f a where -- | A direct specification of bits as an expression. RegisterBitsJustBits :: { -- | Expression for the bits. - justBitsExpr :: Expression Bits stage f a, + justBitsExpr :: ConstExpression Bits stage f a, -- | Annotation for the bits. justBitsAnnot :: a } -> diff --git a/src/Language/Fiddle/Ast/Internal/Util.hs b/src/Language/Fiddle/Ast/Internal/Util.hs index 87fca96..d2be0c3 100644 --- a/src/Language/Fiddle/Ast/Internal/Util.hs +++ b/src/Language/Fiddle/Ast/Internal/Util.hs @@ -52,7 +52,7 @@ identToString = Text.unpack . identifierName directiveToMetadata :: (Annotated (t s)) => Directed t s Identity (Commented SourceSpan) -> - NonEmpty String -> + QualifiedPath String -> Metadata directiveToMetadata (Directed directives t a) qualifiedPath = Metadata diff --git a/src/Language/Fiddle/Compiler/Backend/C.hs b/src/Language/Fiddle/Compiler/Backend/C.hs index df31c8c..f4132c6 100644 --- a/src/Language/Fiddle/Compiler/Backend/C.hs +++ b/src/Language/Fiddle/Compiler/Backend/C.hs @@ -26,6 +26,7 @@ import Data.Text (Text) import qualified Data.Text as Text import Language.Fiddle.Ast import Language.Fiddle.Compiler.Backend +import Language.Fiddle.Compiler.Backend.Internal import Language.Fiddle.Compiler.Backend.Internal.FormattedWriter import qualified Language.Fiddle.Compiler.Backend.Internal.FragTree as FragTree import Language.Fiddle.Compiler.Backend.Internal.Writer @@ -174,8 +175,8 @@ instance IsText String where instance IsText Text where toText = id -qualifiedPathToIdentifier :: (Foldable f, IsText t) => f t -> Text -qualifiedPathToIdentifier = Text.intercalate "_" . map toText . toList +qualifiedPathToIdentifier :: QualifiedPath String -> Text +qualifiedPathToIdentifier = Text.pack . qualifiedPathToString "__" "_" pad :: M () -> M () pad f = text "\n" *> f <* text "\n" @@ -219,9 +220,9 @@ writeRegGet regFullPath = fullPath } ) = do - let fnName = "get_" <> qualifiedPathToIdentifier fullPath + let fnName = qualifiedPathToIdentifier fullPath <> "__get" returnType = sizeToType size - fieldName = NonEmpty.last fullPath + fieldName = basenamePart fullPath case returnType of Just rt -> do @@ -257,16 +258,16 @@ writeRegSet regFullPath = fullPath } ) = do - let fnName = "set_" <> qualifiedPathToIdentifier fullPath + let fnName = qualifiedPathToIdentifier fullPath <> "__set" setType = sizeToType size - fieldName = NonEmpty.last fullPath + fieldName = basenamePart fullPath case setType of Just rt -> do textM $ do tell $ Text.pack $ - printf "static inline void %s(%s* o, %s v) {\n" fnName structType rt + printf "static inline void %s(struct %s* o, %s v) {\n" fnName structType rt tell $ Text.pack $ printf " o->%s = v;\n" fieldName tell "}\n\n" Nothing -> @@ -275,7 +276,7 @@ writeRegSet tell $ Text.pack $ printf - "static inline void %s(%s* o, const uint8_t in[%d]) {\n" + "static inline void %s(struct %s* o, const uint8_t in[%d]) {\n" fnName structType size @@ -283,8 +284,8 @@ writeRegSet tell $ Text.pack $ printf " o->%s[%d] = in[%d];\n" fieldName i i tell "}\n\n" -pattern DefinedBitsP :: String -> NonEmpty String -> N Bits -> RegisterBitsTypeRef Checked f a -> RegisterBitsDecl Checked f a -pattern DefinedBitsP bitsName bitsFullPath offset typeRef <- +pattern DefinedBitsP :: Modifier f a -> String -> QualifiedPath String -> N Bits -> RegisterBitsTypeRef Checked f a -> RegisterBitsDecl Checked f a +pattern DefinedBitsP modifier bitsName bitsFullPath offset typeRef <- ( DefinedBits { qBitsMetadata = Present @@ -294,12 +295,68 @@ pattern DefinedBitsP bitsName bitsFullPath offset typeRef <- FieldSpan { offset = offset }, - bitsFullPath = (NonEmpty.last &&& id -> (bitsName, bitsFullPath)) + bitsFullPath = (basenamePart &&& id -> (bitsName, bitsFullPath)) }, - definedBitsTypeRef = typeRef + definedBitsTypeRef = typeRef, + definedBitsModifier = (Guaranteed modifier) } ) +writeBitsGet :: + StructName -> + String -> + QualifiedPath String -> + N Bits -> + RegisterBitsTypeRef 'Checked I A -> + M () +writeBitsGet _ _ _ _ _ = return () + +writeBitsSet :: + StructName -> + String -> + QualifiedPath String -> + N Bits -> + RegisterBitsTypeRef 'Checked I A -> + M () +writeBitsSet structName bitsNam fullPath offset typeRef = do + text "inline static void " + text (qualifiedPathToIdentifier fullPath) + text "__set(\n struct " + text structName + text " *o,\n " + typeRefToArgs typeRef + text ") {\n" + text "}\n\n" + +typeRefToArgs :: RegisterBitsTypeRef 'Checked I A -> M () +typeRefToArgs reg = + text + $ Text.intercalate ",\n " + $ zipWith + (\n t -> t <> " " <> n) + setterArgumentNames + $ typeRefToArgs' reg + where + typeRefToArgs' + ( RegisterBitsJustBits + { justBitsExpr = ConstExpression (LeftV v) _ + } + ) = [typeForBits v] + typeRefToArgs' + ( RegisterBitsReference + { bitsRefQualificationMetadata = (Identity (Present md)) + } + ) = [qualifiedPathToIdentifier $ metadataFullyQualifiedPath $ getMetadata md] + typeRefToArgs' (RegisterBitsArray tr (ConstExpression (LeftV _) _) _) = + typeRefToArgs' tr ++ ["int"] + + typeForBits = \case + 64 -> "uint64_t" + 32 -> "uint32_t" + 16 -> "uint16_t" + 8 -> "uint8_t" + _ -> "unsigend" + -- | Decomposes a type ref into a type name (String) and a list of dimensions -- (in the case of being an array) -- decomposeBitsTypeRef :: RegisterBitsTypeRef Checked I A -> (String, [N Unitless]) @@ -310,14 +367,21 @@ writeRegisterBody structName regmeta = walk_ registerWalk registerWalk :: forall t. (Walk t, Typeable t) => t I A -> M () registerWalk t = case () of () - | (Just (DefinedBitsP bitsName fullPath offset typeRef)) <- castTS t -> - text $ - Text.pack $ - printf - "// Emit bits %s (%s) at %d\n" - bitsName - (qualifiedPathToIdentifier fullPath) - offset + | (Just (DefinedBitsP modifier bitsName fullPath offset typeRef)) <- castTS t -> do + sequence_ $ + selectByModifier + modifier + ( writeBitsGet structName bitsName fullPath offset typeRef, + writeBitsSet structName bitsName fullPath offset typeRef + ) + + -- text $ + -- Text.pack $ + -- printf + -- "// Emit bits %s (%s) at %d\n" + -- bitsName + -- (qualifiedPathToIdentifier fullPath) + -- offset _ -> return () castTS :: diff --git a/src/Language/Fiddle/Compiler/Backend/Internal.hs b/src/Language/Fiddle/Compiler/Backend/Internal.hs new file mode 100644 index 0000000..4e513f1 --- /dev/null +++ b/src/Language/Fiddle/Compiler/Backend/Internal.hs @@ -0,0 +1,18 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Language.Fiddle.Compiler.Backend.Internal where + +import qualified Data.Text + +-- | An infinite list of common setter argument names to use. +setterArgumentNames :: [Data.Text.Text] +setterArgumentNames = + ["value", "i", "j", "k"] + ++ map (("i" <>) . Data.Text.pack . show) [(0 :: Int) ..] + +-- | An infinite list of common getter argument names to use. A getter will have +-- an argument for each index into an array for bit arrays. +getterArgumentNames :: [Data.Text.Text] +getterArgumentNames = + ["i", "j", "k"] + ++ map (("i" <>) . Data.Text.pack . show) [(0 :: Int) ..] diff --git a/src/Language/Fiddle/Compiler/ConsistencyCheck.hs b/src/Language/Fiddle/Compiler/ConsistencyCheck.hs index 6a3b5d9..a8d9758 100644 --- a/src/Language/Fiddle/Compiler/ConsistencyCheck.hs +++ b/src/Language/Fiddle/Compiler/ConsistencyCheck.hs @@ -266,8 +266,7 @@ bitsTypeSize QMdP (ExportedBitsDecl {exportedBitsDeclSizeBits = sz}) } = return sz bitsTypeSize (RegisterBitsReference {}) = error "should be exhaustive" -bitsTypeSize (RegisterBitsJustBits expr _) = - expressionToIntM expr +bitsTypeSize (RegisterBitsJustBits expr _) = return $ trueValue expr checkSizeMismatch :: (NamedUnit u) => A -> N u -> N u -> Compile s () checkSizeMismatch _ a b | a == b = return () diff --git a/src/Language/Fiddle/Compiler/Qualification.hs b/src/Language/Fiddle/Compiler/Qualification.hs index 56f1122..1307c2a 100644 --- a/src/Language/Fiddle/Compiler/Qualification.hs +++ b/src/Language/Fiddle/Compiler/Qualification.hs @@ -37,6 +37,8 @@ data GlobalState = GlobalState data LocalState = LocalState { currentScopePath :: ScopePath String, + -- | Current qualified path, used for building metadata. + currentQualifiedPath :: QualifiedPath (), ephemeralScope :: Scope String (Metadata, ExportedDecl) } @@ -62,29 +64,62 @@ instance CompilationStage Expanded where type StageFunctor Expanded = F type StageAnnotation Expanded = A +pushPackage :: NonEmpty String -> LocalState -> (QualifiedPath String, LocalState) +pushPackage pk ls = + let q = currentQualifiedPath ls + in ( qualifyPackage pk, + ls + { currentScopePath = pushScope pk (currentScopePath ls), + currentQualifiedPath = + q + { packagePart = packagePart q ++ NonEmpty.toList pk + } + } + ) + where + qualifyPackage :: NonEmpty String -> QualifiedPath String + qualifyPackage (NonEmpty.reverse -> (l :| (reverse -> h))) = + let q = currentQualifiedPath ls + in q {packagePart = packagePart q ++ h, basenamePart = l} + +pushObject :: String -> LocalState -> (QualifiedPath String, LocalState) +pushObject objName ls = + let q = currentQualifiedPath ls + in ( fmap (const objName) q, + ls + { currentScopePath = pushScope (NonEmpty.singleton objName) (currentScopePath ls), + currentQualifiedPath = + q + { objectPart = Just objName + } + } + ) + +pushRegister :: String -> LocalState -> (QualifiedPath String, LocalState) +pushRegister regName ls = + let q = currentQualifiedPath ls + in ( fmap (const regName) q, + ls + { currentScopePath = pushScope (NonEmpty.singleton regName) (currentScopePath ls), + currentQualifiedPath = + q + { registerPart = registerPart q ++ [regName] + } + } + ) + qualificationPhase :: CompilationPhase Expanded Qualified qualificationPhase = - pureCompilationPhase $ \t -> do - raw <- - fmap snd $ - subCompile (GlobalState mempty 0) $ - advanceStage - (LocalState mempty mempty) - (soakA t) - - squeezeDiagnostics raw - -pushIdent :: Identifier f a -> LocalState -> LocalState -pushIdent i = pushIdents [i] - -pushIdents :: (Foldable t) => t (Identifier f a) -> LocalState -> LocalState -pushIdents = - ( \case - [] -> id - (i : is) -> - modifyCurrentScopePath (pushScope $ fmap identToString (i :| is)) - ) - . toList + let initialQualifiedPath = QualifiedPath [] Nothing [] () + in pureCompilationPhase $ \t -> do + raw <- + fmap snd $ + subCompile (GlobalState mempty 0) $ + advanceStage + (LocalState mempty initialQualifiedPath mempty) + (soakA t) + + squeezeDiagnostics raw instance StageConvertible @@ -98,7 +133,7 @@ instance AdvanceStage S (ConstExpression u) where advanceStage ls (ConstExpression (RightV exp) a) = case exp of Var var _ -> do - (_, ExportedLocationDecl _ v) <- resolveOrFail =<< resolveName var ls + (ExportedLocationDecl _ v) <- resolveOrFail =<< resolveName var ls return $ ConstExpression (LeftV $ fromIntegral v) a LitNum (RightV v) _ -> return $ ConstExpression (LeftV v) a @@ -127,15 +162,13 @@ instance AdvanceStage S RegisterBitsDecl where <*> pure name <*> pure an DefinedBits _ mod ident typ an -> do - let qMeta = + let (path, _) = pushObject (identToString ident) localState + qMeta = QBitsMetadata { bitsSpan = Vacant, - bitsFullPath = - qualifyPath - (currentScopePath localState) - (NonEmpty.singleton (identToString ident)) + bitsFullPath = path } - DefinedBits (Present qMeta) mod ident + DefinedBits (Present qMeta) (guarantee (ModifierKeyword Rw an) mod) ident <$> advanceStage localState typ <*> pure an @@ -145,38 +178,39 @@ instance AdvanceStage S ObjTypeDecl where AssertPosStatement d <$> advanceStage localState e <*> pure a RegisterDecl _ mod ident size bod ann -> do ident' <- guaranteeM (uniqueIdentifier "reg" ann) ident - let localState' = pushIdents ident localState + + let (qualified, localState') = + pushRegister (identToString $ unwrap ident') localState + -- Avoid pushing the anonymized name onto the stack. + localState'' = + if isNothing (toMaybe ident) then localState else localState' let qRegMeta = QRegMetadata { regSpan = Vacant, regIsPadding = False, regIsUnnamed = isNothing (toMaybe ident), - regFullPath = - qualifyPath - (currentScopePath localState) - (NonEmpty.singleton (identToString (unwrap ident'))) + regFullPath = qualified } RegisterDecl (Present qRegMeta) (guarantee (ModifierKeyword Rw ann) mod) ident' - <$> advanceStage localState' size - <*> mapM (advanceStage localState') bod + <$> advanceStage localState'' size + <*> mapM (advanceStage localState'') bod <*> pure ann ReservedDecl _ expr ann -> do ident <- uniqueIdentifier "reserved" ann + let (q, _) = pushRegister (identToString ident) localState + let qRegMeta = QRegMetadata { regSpan = Vacant, regIsPadding = True, regIsUnnamed = True, - regFullPath = - qualifyPath - (currentScopePath localState) - (NonEmpty.singleton (identToString ident)) + regFullPath = q } RegisterDecl @@ -187,7 +221,11 @@ instance AdvanceStage S ObjTypeDecl where <*> pure Nothing <*> pure ann TypeSubStructure bod name an -> do - let localState' = pushIdents name localState + let localState' = + maybe + localState + (\n -> snd $ pushRegister (identToString n) localState) + name TypeSubStructure <$> mapM (advanceStage localState') bod <*> pure name @@ -207,7 +245,7 @@ instance AdvanceStage S RegisterBitsTypeRef where <$> advanceStage localState a <*> pure b RegisterBitsReference _ name a -> do - v <- fmap (Present . snd) <$> resolveName name localState + v <- fmap Present <$> resolveName name localState return $ RegisterBitsReference v name a instance AdvanceStage S ObjType where @@ -218,7 +256,7 @@ instance AdvanceStage S ObjType where <*> advanceStage localState b <*> pure c ReferencedObjType _ name a -> do - v <- fmap (Present . snd) <$> resolveName name localState + v <- fmap Present <$> resolveName name localState return $ ReferencedObjType v name a deriving instance (AdvanceStage S t) => AdvanceStage S (Directed t) @@ -246,13 +284,13 @@ modifyCurrentScopePath :: modifyCurrentScopePath fn ls@LocalState {currentScopePath = cs} = ls {currentScopePath = fn cs} -resolveIdent :: (ExportableDecl d, Functor f) => Identifier f A -> LocalState -> M (F ([String], d)) +resolveIdent :: (ExportableDecl d, Functor f) => Identifier f A -> LocalState -> M (F d) resolveIdent i = resolveSymbol (annot i) [identToString i] -resolveName :: (ExportableDecl d, Functor f) => Name f A -> LocalState -> M (F ([String], d)) +resolveName :: (ExportableDecl d, Functor f) => Name f A -> LocalState -> M (F d) resolveName n = resolveSymbol (annot n) (toList $ nameToList n) -resolveSymbol :: (ExportableDecl d) => A -> [String] -> LocalState -> M (F ([String], d)) +resolveSymbol :: (ExportableDecl d) => A -> [String] -> LocalState -> M (F d) resolveSymbol a (p : ps) (LocalState {ephemeralScope = ephemeralScope, currentScopePath = currentPath}) = do GlobalState {unitInterface = UnitInterface {rootScope = rootScope}} <- get @@ -265,7 +303,7 @@ resolveSymbol a (p : ps) (LocalState {ephemeralScope = ephemeralScope, currentSc return $ case matches of - [(p, (_, e))] -> Right (toList p, e) + [(_, (_, e))] -> Right e [] -> Left [ Diagnostic @@ -307,7 +345,7 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do M ([Directed FiddleDecl Qualified F A], LocalState) doReturn v = return (Directed directives v dann : declsRet, localState') doReturnWith s v = return (Directed directives v dann : declsRet, s) - qualify = qualifyPath (currentScopePath localState') + metadata = directiveToMetadata d in case t of UsingDecl {usingName = name} -> @@ -320,8 +358,10 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do <$> advanceStage localState'' st <*> pure a PackageDecl _ name body ann -> - let qualifiedName = qualify (nameToList name) - localState'' = modifyCurrentScopePath (pushScope (nameToList name)) localState' + let (qualifiedName, localState'') = + pushPackage + (nameToList name) + localState' decl = ExportedPackageDecl (metadata qualifiedName) in do insertDecl decl @@ -332,7 +372,10 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do <$> mapM (advanceStage localState'') body <*> pure ann LocationDecl _ ident expr ann -> - let qualifiedName = qualify (NonEmpty.singleton (identToString ident)) + let qualifiedName = + fmap + (const $ identToString ident) + (currentQualifiedPath localState') in do expr' <- advanceStage localState' expr let decl = @@ -347,7 +390,10 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do <$> advanceStage localState' expr <*> pure ann BitsDecl _ ident typ ann -> - let qualifiedName = qualify (NonEmpty.singleton (identToString ident)) + let qualifiedName = + fmap + (const $ identToString ident) + (currentQualifiedPath localState) in do sizeBits <- getBitTypeDeclaredSize typ let decl = @@ -362,11 +408,10 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do <$> advanceStage localState' typ <*> pure ann ObjTypeDecl _ ident body ann -> - let qualifiedName = qualify (NonEmpty.singleton (identToString ident)) - localState'' = - modifyCurrentScopePath - (pushScope (NonEmpty.singleton $ identToString ident)) - localState' + let (qualifiedName, localState'') = + pushObject + (identToString ident) + localState in do typeSize <- calculateTypeSize =<< resolveOrFail body let decl = @@ -381,7 +426,10 @@ advanceFiddleDecls localState decls = fmap (reverse . fst) $ do <$> mapM (advanceStage localState'') body <*> pure ann ObjectDecl _ ident loc typ ann -> - let qualifiedName = qualify (NonEmpty.singleton (identToString ident)) + let qualifiedName = + fmap + (const $ identToString ident) + (currentQualifiedPath localState) in do location <- resolveLocationExpression localState' loc typ' <- advanceStage localState' typ @@ -414,10 +462,8 @@ objTypeToExport ls = \case <$> objTypeToExport ls objType <*> pure (trueValue size) ReferencedObjType {refName = n} -> do - (full, _ :: ExportedTypeDecl) <- resolveOrFail =<< resolveName n ls - case full of - (f : fs) -> return $ ReferencedObjectType (f :| fs) - _ -> compilationFailure + (td :: ExportedTypeDecl) <- resolveOrFail =<< resolveName n ls + return $ ReferencedObjectType (metadataFullyQualifiedPath $ getMetadata td) calculateTypeSize :: ObjTypeBody Expanded F A -> M (N Bytes) calculateTypeSize (ObjTypeBody bodyType decls _) = @@ -446,7 +492,7 @@ resolveLocationExpression :: Expression u stage F A -> M (N u) resolveLocationExpression ls (Var var _) = do - (_, ExportedLocationDecl _ v) <- resolveOrFail =<< resolveName var ls + (ExportedLocationDecl _ v) <- resolveOrFail =<< resolveName var ls return (fromIntegral v) resolveLocationExpression _ e = expressionToIntM e diff --git a/src/Language/Fiddle/GenericTree.hs b/src/Language/Fiddle/GenericTree.hs index 9b3089b..7e8d79b 100644 --- a/src/Language/Fiddle/GenericTree.hs +++ b/src/Language/Fiddle/GenericTree.hs @@ -276,4 +276,6 @@ deriving instance (Context stage) => (ToGenericSyntaxTree (ConstExpression Unitl deriving instance (Context stage) => (ToGenericSyntaxTree (ConstExpression Address stage)) +deriving instance (Context stage) => (ToGenericSyntaxTree (ConstExpression Bits stage)) + deriving instance (Context stage) => (ToGenericSyntaxTree (Expression u stage)) diff --git a/src/Language/Fiddle/Internal/UnitInterface.hs b/src/Language/Fiddle/Internal/UnitInterface.hs index 42ce810..1302e40 100644 --- a/src/Language/Fiddle/Internal/UnitInterface.hs +++ b/src/Language/Fiddle/Internal/UnitInterface.hs @@ -1,14 +1,20 @@ +{-# LANGUAGE DeriveFoldable #-} +{-# LANGUAGE DeriveTraversable #-} + module Language.Fiddle.Internal.UnitInterface where import Data.Aeson +import Data.List (intercalate) import Data.List.NonEmpty (NonEmpty) -import Data.Text +import qualified Data.List.NonEmpty as NonEmpty +import Data.Maybe (fromMaybe, maybeToList) +import qualified Data.Text import Data.Word import GHC.Generics import Language.Fiddle.Internal.Scopes (Scope) import qualified Language.Fiddle.Internal.Scopes as Scopes -import Language.Fiddle.Types (SourceSpan) import Language.Fiddle.Internal.UnitNumbers +import Language.Fiddle.Types (SourceSpan) data InternalDirectiveExpression = InternalDirectiveExpressionNumber String @@ -31,16 +37,45 @@ data InternalDirective = InternalDirective } deriving (Generic, ToJSON, FromJSON, Show, Eq, Ord) +data QualifiedPath a = QualifiedPath + { -- | The part of the qualified path that belongs to the package. + packagePart :: [String], + -- | The part of the qualified path that belongs to the object. + objectPart :: Maybe String, + -- | The part of the qualified path that belongs to a register. + registerPart :: [String], + -- | The basename (unqualified path) + basenamePart :: a + } + deriving (Generic, ToJSON, FromJSON, Show, Eq, Ord, Functor) + +qualifiedPathToString :: String -> String -> QualifiedPath String -> String +qualifiedPathToString majorSeparator minorSeparator qp = + intercalate majorSeparator $ + map (intercalate minorSeparator) $ + filter + (not . null) + [ packagePart qp, + maybeToList (objectPart qp), + registerPart qp, + [basenamePart qp] + ] + +-- | Turn a QualifiedPath with a string to a String list for scope lookups. +qualifiedPathToList :: QualifiedPath String -> NonEmpty String +qualifiedPathToList (QualifiedPath package obj reg base) = + NonEmpty.prependList (package ++ maybeToList obj ++ reg) (NonEmpty.singleton base) + -- | Metadata about an exported value. This includes things like the source -- location, doc comments and compiler directives associated with the exported -- symbol. data Metadata = Metadata { -- | Fully-qualified path the the element. - metadataFullyQualifiedPath :: NonEmpty String, + metadataFullyQualifiedPath :: QualifiedPath String, -- | Source location for the exported symbol. metadataSourceSpan :: SourceSpan, -- | Doc comment associated with the symbol. - metadataDocComment :: Text, + metadataDocComment :: Data.Text.Text, -- | List of directives associated with this exported symbol. metadataDirectives :: [InternalDirective] } @@ -61,12 +96,12 @@ data UnitInterface where insert :: (ExportableDecl d) => d -> UnitInterface -> UnitInterface insert decl (UnitInterface sc deps) = let metadata = getMetadata decl - path = metadataFullyQualifiedPath metadata + path = qualifiedPathToList (metadataFullyQualifiedPath metadata) in UnitInterface (Scopes.insertScope path (metadata, toExportedDecl decl) sc) deps singleton :: (ExportableDecl d) => d -> UnitInterface singleton decl = - let path = metadataFullyQualifiedPath (getMetadata decl) + let path = qualifiedPathToList (metadataFullyQualifiedPath (getMetadata decl)) metadata = getMetadata decl in UnitInterface (Scopes.singleton path (metadata, toExportedDecl decl)) [] @@ -125,7 +160,7 @@ data ExportedTypeDecl where data ReferencedObjectType where ReferencedObjectType :: - {objectTypeReference :: NonEmpty String} -> ReferencedObjectType + {objectTypeReference :: QualifiedPath String} -> ReferencedObjectType ArrayObjectType :: { arrayObjectTypeType :: ReferencedObjectType, arrayObjectTypeNumber :: N Unitless @@ -192,6 +227,17 @@ instance ExportableDecl ExportedObjectDecl where _ -> Nothing getMetadata = exportedObjectDeclMetadata +instance ExportableDecl ExportedDecl where + toExportedDecl = id + fromExportedDecl = Just + getMetadata = + \case + ExportedPackage e -> getMetadata e + ExportedLocation e -> getMetadata e + ExportedBits e -> getMetadata e + ExportedType e -> getMetadata e + ExportedObject e -> getMetadata e + -- | A generalized representation of different exported declarations. -- This data type allows for a uniform way to handle various exportable -- syntax tree elements (e.g., packages, locations, bits, types, objects). diff --git a/src/Language/Fiddle/Parser.hs b/src/Language/Fiddle/Parser.hs index dea2dd5..7ef5ac4 100644 --- a/src/Language/Fiddle/Parser.hs +++ b/src/Language/Fiddle/Parser.hs @@ -190,6 +190,9 @@ objTypeP = do AnonymousObjType Witness <$> defer body (objTypeBodyP t) ) +asConstP :: Pa (Expression u) -> Pa (ConstExpression u) +asConstP fn = withMeta $ ConstExpression . RightV <$> fn + exprInParenP :: Pa (Expression u) exprInParenP = tok TokLParen *> expressionP <* tok TokRParen @@ -258,7 +261,7 @@ registerBitsDeclP = tok KWReserved >> ReservedBits <$> exprInParenP ) <|> (BitsSubStructure <$> registerBodyP <*> optionMaybe ident) - <|> ( DefinedBits Vacant + <|> ( DefinedBits Vacant . Perhaps <$> optionMaybe modifierP <*> ident <*> (tok TokColon >> registerBitsTypeRefP) @@ -282,7 +285,7 @@ registerBitsTypeRefP = do baseTypeRef = withMeta $ - (RegisterBitsJustBits <$> exprInParenP) + (RegisterBitsJustBits <$> asConstP exprInParenP) <|> (RegisterBitsAnonymousType Witness <$> anonymousBitsTypeP) <|> (RegisterBitsReference noQMd <$> name) |