| ID | f951e008-a3e7-4432-9df8-ecf4e3b586f7 |
|---|---|
| DeertopiaVisibility | public |
| ROAM_ALIASES | Sixty |
| ROAM_REFS | https://github.com/ollef/sixten https://github.com/ollef/sixty |
Sixten
Sixten is a dependently-typed functional programming language keen on performance. It's relevance to SydML is found in its demand-driven architecture.
Implementation details
| ID | c66a817f-ae43-4b28-8304-889696028061 |
|---|---|
| DeertopiaVisibility | public |
| ROAM_EXCLUDE | t |
Types
Names
Lowered
data Lowered = Lowered !Lifted !LoweredKind
deriving (Eq, Ord, Show, Generic)
[?] What is LoweredKind for?
Lifted
data Lifted = Lifted !Qualified !Int
deriving (Eq, Ord, Show, Generic)
Fully qualified.
[?] What is the associated integer for? If you search for references to the Lifted constructor, you'll find many instances of the Int component simply being a literal 0, leading me to believe it is not used as a unique identifier.
Scope
An alias for HashMap Name.Surface Entry
Entry
Entry represents members of the scope. Most relevantly, qualified names, and sets of ambiguous names.
Queries
digraph sixty_queries {
bgcolor="transparent"
node [
style=filled
fillcolor=gray95
]
ModuleFile -> InputFiles
ModuleFile -> SourceDirectories
ParsedFile -> FileText
ParsedFile -> SourceDirectories
ModuleDefinitions -> ModuleFile
ModuleDefinitions -> ParsedFile
ModuleHeader -> ModuleFile
ModuleHeader -> ParsedFile
ModuleHeader -> ModuleFile
ImportedNames -> ImportedNames
ImportedNames -> ModuleHeader
ImportedNames -> ModuleHeader
ImportedNames -> ModuleScope
NameAliases -> ImportedNames
NameAliases -> ModuleScope
ParsedDefinition -> ParsedDefinition
ParsedDefinition -> ModuleFile
ParsedDefinition -> ParsedFile
ModulePositionMap -> ModuleSpanMap
ModuleSpanMap -> ModuleFile
ModuleSpanMap -> FileText
ModuleSpanMap -> ParsedFile
ModuleScope -> ModuleFile
ModuleScope -> ParsedFile
ModuleScope -> "Resolution.moduleScopes"
"Resolution.moduleScopes" [ shape="record" ]
ResolvedName -> ModuleScope
ResolvedName -> ImportedNames
ElaboratingDefinition -> ParsedDefinition
ElaboratingDefinition -> ParsedDefinition
ElaboratingDefinition -> ElaboratedType
ElaboratingDefinition -> ElaboratedType
ElaboratedType -> ElaboratingDefinition
ElaboratedType -> ElaboratedDefinition
ElaboratedType -> ElaboratedType
ElaboratedDefinition -> ElaboratingDefinition
ElaboratedDefinition -> ElaboratedType
Dependencies -> Dependencies
Dependencies -> ElaboratedDefinition
TransitiveDependencies -> TransitiveDependencies
TransitiveDependencies -> TransitiveDependencies
TransitiveDependencies -> Dependencies
TransitiveDependencies -> Dependencies
ConstructorType -> ElaboratedDefinition
DefinitionPosition -> ModulePositionMap
DefinitionPosition -> ModuleFile
Occurrences -> Occurrences
Occurrences -> Occurrences
LambdaLifted -> ElaboratedDefinition
LambdaLiftedDefinition -> LambdaLifted
LambdaLiftedDefinition -> LambdaLifted
LambdaLiftedDefinition -> LambdaLifted
LambdaLiftedModuleDefinitions -> ModuleDefinitions
LambdaLiftedModuleDefinitions -> LambdaLifted
ClosureConverted -> LambdaLiftedDefinition
ClosureConvertedType -> ClosureConverted
ClosureConvertedType -> ClosureConverted
ClosureConvertedType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConvertedConstructorType
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConverted
ClosureConvertedConstructorType -> ClosureConvertedConstructorType
ClosureConvertedConstructorType -> ClosureConvertedConstructorType
LowSignature -> ClosureConverted
LowSignature -> ClosureConverted
LoweredDefinitions -> ClosureConverted
LoweredDefinitions -> "Lower.definition"
"Lower.definition" [ shape="record" ]
"Lower.definition" -> LowSignature
"Lower.definition" -> ConstructorRepresentations
"Lower.definition" -> ClosureConvertedConstructorType
ConstructorRepresentations -> ClosureConverted
ConstructorRepresentation -> ConstructorRepresentations
LowDefinitions -> ClosureConverted
LowModule -> LambdaLiftedModuleDefinitions
LowModule -> LowDefinitions
ReferenceCountedLowModule -> LowModule
LLVMModule -> ReferenceCountedLowModule
LLVMModuleInitModule -> InputFiles
LLVMModuleInitModule -> ParsedFile
ElaboratingDefinition -> "Elaboration.checkDefinition"
"Elaboration.checkDefinition" [ shape="record" ]
"Elaboration.checkDefinition" -> "Elaboration.check"
"Elaboration.elaborateWith" [ shape="record" ]
"Elaboration.elaborateWith" -> "Elaboration.elaborate"
"Elaboration.elaborateWith" -> ResolvedName
"Elaboration.elaborateWith" -> ElaboratedType
"Elaboration.elaborateWith" -> ConstructorType
"Elaboration.elaborate" [ shape="record" ]
"Elaboration.infer" [ shape="record" ]
"Elaboration.infer" -> "Elaboration.elaborate"
"Elaboration.check" -> "Elaboration.elaborate"
"Elaboration.elaborate" -> "Elaboration.elaborateWith"
"Elaboration.check" -> "Elaboration.elaborate"
"Elaboration.check" [ shape="record" ]
}
file:sixty-query-call-graph.png
ModuleDefinitions
ModuleDefinitions :: Name.Module -> Query (OrderedHashSet Name)
Given a Name.Module, fetch the unresolved names of each definition.
LambdaLiftedModuleDefinitions
LambdaLiftedModuleDefinitions :: Name.Module -> Query (OrderedHashSet Name.Lifted)
Given a Name.Module, lambda-lift all definitions, and return their (fully-qualified!) names.
LambdaLiftedModuleDefinitions module_ ->
noError do
names <- fetch $ ModuleDefinitions module_
OrderedHashSet.fromList . concat
<$> forM (toList names) \name -> do
let qualifiedName =
-- Each name from the source module is adorned with the module
-- name.
Name.Qualified module_ name
(_, extras) <- fetch $ LambdaLifted qualifiedName
-- I'm not sure what's going on with the EnumMap here...
pure $ Name.Lifted qualifiedName <$> 0 : EnumMap.keys extras
Mysteriously, lambda-lifting occurs before closure-conversion...
ResolvedName
ResolvedName :: Name.Module -> Name.Surface -> Query (Maybe Scope.Entry)
Given the module of occurence, and the unresolved name, return the resolved under the scope of the given module. Does not error, and does not account for local variables.
ResolvedName module_ surfaceName ->
noError do
-- Notice the particular use of privateScope!
(privateScope, _) <- fetch $ ModuleScope module_
importedScopeEntry <- fetchImportedName module_ surfaceName
pure $ importedScopeEntry <> HashMap.lookup surfaceName privateScope
ModuleScope
ModuleScope :: Name.Module -> Query (Scope, Scope)
ModuleScope moduleName is a query returning a pair (privateScope, publicScope).
ImportedNames
ImportedNames :: Name.Module -> Mapped.Query Name.Surface Scope.Entry a -> Query a
Fetch the union of all names exposed by a given module's imports.
ImportedNames module_ subQuery ->
noError $
Mapped.rule (ImportedNames module_) subQuery do
header <- fetch $ ModuleHeader module_
scopes <- forM header.imports \import_ -> do
importedHeader <- fetch $ ModuleHeader import_.module_
(_, publicScope) <- fetch $ ModuleScope import_.module_
pure $
Resolution.importedNames import_ $
Resolution.exposedNames importedHeader.exposedNames publicScope
pure $ foldl' (HashMap.unionWith (<>)) mempty scopes
Driver
See: src/Compiler.hs Some key takeaways:
The set of source files is fetched with a query.
Source files appear to be processed in arbitrary order, with no regard to dependency graphs. I believe Sixty's query-based architecture is capable of handling dependencies implicitly.
Contrary to the intuition that comes with a background in traditional batch compilers, the "pipeline's" entry point is the query corresponding to the final pass (LLVMModule).
-- NB this code has been heavily modified for brevity!
compile :: ... -> Task Query ()
compile = do
filePaths <- fetch Query.InputFiles
moduleLLVMFiles <- forM (toList filePaths) \filePath -> do
(moduleName@(Name.Module moduleNameText), _, _) <- fetch $ Query.ParsedFile filePath
when printLowered do
{- Debug printing logic omitted. -}
llvmModule <- fetch $ Query.LLVMModule moduleName
let llvmFileName = moduleAssemblyDir </> toS moduleNameText <.> "ll"
liftIO $ Lazy.writeFile llvmFileName llvmModule
pure llvmFileName
Name resolution
Name resolution occurs lazily, somewhere between the ModuleDefinitions and LambdaLiftedModuleDefinitions queries.