// conductParsing performs parsing of a source file found at the given path. func (p *PackageLoader) conductParsing(sourceFile pathInformation) { inputSource := compilercommon.InputSource(sourceFile.path) // Add the file to the package map as a package of one file. p.packageMap.Add(sourceFile.sourceKind, sourceFile.referenceId, PackageInfo{ kind: sourceFile.sourceKind, referenceId: sourceFile.referenceId, modulePaths: []compilercommon.InputSource{inputSource}, }) // Ensure the file exists. if ok, _ := exists(sourceFile.path); !ok { p.errors <- compilercommon.SourceErrorf(sourceFile.sal, "Could not find source file '%s'", sourceFile.path) return } // Load the source file's contents. contents, err := ioutil.ReadFile(sourceFile.path) if err != nil { p.errors <- compilercommon.SourceErrorf(sourceFile.sal, "Could not load source file '%s'", sourceFile.path) return } // Parse the source file. handler, hasHandler := p.handlers[sourceFile.sourceKind] if !hasHandler { log.Fatalf("Missing handler for source file of kind: [%v]", sourceFile.sourceKind) } handler.Parse(inputSource, string(contents), p.handleImport) }
func (sh *srgSourceHandler) Verify(errorReporter packageloader.ErrorReporter, warningReporter packageloader.WarningReporter) { g := sh.srg // Collect any parse errors found and add them to the result. eit := g.findAllNodes(parser.NodeTypeError).BuildNodeIterator( parser.NodePredicateErrorMessage, parser.NodePredicateSource, parser.NodePredicateStartRune) for eit.Next() { sal := salForIterator(eit) errorReporter(compilercommon.NewSourceError(sal, eit.GetPredicate(parser.NodePredicateErrorMessage).String())) } // Verify all 'from ... import ...' are valid. fit := g.findAllNodes(parser.NodeTypeImportPackage). Has(parser.NodeImportPredicateSubsource). BuildNodeIterator(parser.NodeImportPredicateSubsource, parser.NodePredicateSource, parser.NodePredicateStartRune) for fit.Next() { // Load the package information. packageInfo := g.getPackageForImport(fit.Node()) if !packageInfo.IsSRGPackage() { continue } // Search for the subsource. subsource := fit.GetPredicate(parser.NodeImportPredicateSubsource).String() _, found := packageInfo.FindTypeOrMemberByName(subsource) if !found { source := fit.Node().GetIncomingNode(parser.NodeImportPredicatePackageRef).Get(parser.NodeImportPredicateSource) sal := salForIterator(fit) errorReporter(compilercommon.SourceErrorf(sal, "Import '%s' not found under package '%s'", subsource, source)) } } // Build the map for globally aliased types. ait := g.findAllNodes(parser.NodeTypeDecorator). Has(parser.NodeDecoratorPredicateInternal, aliasInternalDecoratorName). BuildNodeIterator() for ait.Next() { // Find the name of the alias. decorator := ait.Node() parameter, ok := decorator.TryGetNode(parser.NodeDecoratorPredicateParameter) if !ok || parameter.Kind() != parser.NodeStringLiteralExpression { sal := salForNode(decorator) errorReporter(compilercommon.SourceErrorf(sal, "Alias decorator requires a single string literal parameter")) continue } var aliasName = parameter.Get(parser.NodeStringLiteralExpressionValue) aliasName = aliasName[1 : len(aliasName)-1] // Remove the quotes. aliasedType := SRGType{decorator.GetIncomingNode(parser.NodeTypeDefinitionDecorator), g} g.aliasMap[aliasName] = aliasedType } }
// loadVCSPackage loads the package found at the given VCS path. func (p *PackageLoader) loadVCSPackage(packagePath pathInformation) { // Lock on the package path to ensure no other checkouts occur for this path. pathLock := p.vcsLockMap.GetLock(packagePath.path) pathLock.Lock() defer pathLock.Unlock() existingCheckoutDir, exists := p.vcsPathsLoaded.Get(packagePath.path) if exists { // Note: existingCheckoutDir will be empty if there was an error loading the VCS. if existingCheckoutDir != "" { // Push the now-local directory onto the package loading channel. p.pushPathWithId(packagePath.referenceId, packagePath.sourceKind, pathLocalPackage, existingCheckoutDir.(string), packagePath.sal) return } } rootDirectory := path.Dir(p.rootSourceFile) pkgDirectory := path.Join(rootDirectory, SerulianPackageDirectory) // Perform the checkout of the VCS package. checkoutDirectory, err, warning := vcs.PerformVCSCheckout(packagePath.path, pkgDirectory, p.vcsDevelopmentDirectories...) if err != nil { p.vcsPathsLoaded.Set(packagePath.path, "") p.errors <- compilercommon.SourceErrorf(packagePath.sal, "Error loading VCS package '%s': %v", packagePath.path, err) return } p.vcsPathsLoaded.Set(packagePath.path, checkoutDirectory) if warning != "" { p.warnings <- compilercommon.NewSourceWarning(packagePath.sal, warning) } // Push the now-local directory onto the package loading channel. p.pushPathWithId(packagePath.referenceId, packagePath.sourceKind, pathLocalPackage, checkoutDirectory, packagePath.sal) }
// loadLocalPackage loads the package found at the path relative to the package directory. func (p *PackageLoader) loadLocalPackage(packagePath pathInformation) { // Ensure the directory exists. if ok, _ := exists(packagePath.path); !ok { p.errors <- compilercommon.SourceErrorf(packagePath.sal, "Could not find directory '%s'", packagePath.path) return } // Read the contents of the directory. directoryContents, err := ioutil.ReadDir(packagePath.path) if err != nil { p.errors <- compilercommon.SourceErrorf(packagePath.sal, "Could not load directory '%s'", packagePath.path) return } // Add the package information to the map. packageInfo := &PackageInfo{ kind: packagePath.sourceKind, referenceId: packagePath.referenceId, modulePaths: make([]compilercommon.InputSource, 0), } // Load the handler for the package. handler, hasHandler := p.handlers[packagePath.sourceKind] if !hasHandler { log.Fatalf("Missing handler for source file of kind: [%v]", packagePath.sourceKind) } // Find all source files in the directory and add them to the paths list. var fileFound bool for _, fileInfo := range directoryContents { if path.Ext(fileInfo.Name()) == handler.PackageFileExtension() { fileFound = true filePath := path.Join(packagePath.path, fileInfo.Name()) p.pushPath(pathSourceFile, packagePath.sourceKind, filePath, packagePath.sal) // Add the source file to the package information. packageInfo.modulePaths = append(packageInfo.modulePaths, compilercommon.InputSource(filePath)) } } p.packageMap.Add(packagePath.sourceKind, packagePath.referenceId, *packageInfo) if !fileFound { p.warnings <- compilercommon.SourceWarningf(packagePath.sal, "Package '%s' has no source files", packagePath.path) return } }
// handleImport queues an import found in a source file. func (p *PackageLoader) handleImport(importInformation PackageImport) string { handler, hasHandler := p.handlers[importInformation.Kind] if !hasHandler { p.errors <- compilercommon.SourceErrorf(importInformation.SourceLocation, "Unknown kind of import '%s'", importInformation.Kind) return "" } sourcePath := string(importInformation.SourceLocation.Source()) if importInformation.ImportType == ImportTypeVCS { // VCS paths get added directly. return p.pushPath(pathVCSPackage, importInformation.Kind, importInformation.Path, importInformation.SourceLocation) } else { // Check the path to see if it exists as a single source file. If so, we add it // as a source file instead of a local package. currentDirectory := path.Dir(sourcePath) dirPath := path.Join(currentDirectory, importInformation.Path) filePath := dirPath + handler.PackageFileExtension() var importedDirectoryPath = dirPath var title = "package" // Determine if path refers to a single source file. If so, it is imported rather than // the entire directory. isSourceFile, _ := exists(filePath) if isSourceFile { title = "module" importedDirectoryPath = path.Dir(filePath) } // Check to ensure we are not crossing a VCS boundary. if currentDirectory != importedDirectoryPath { // If the imported directory is underneath the current directory, we need to walk upward. if strings.HasPrefix(importedDirectoryPath, currentDirectory) { err := p.verifyNoVCSBoundaryCross(importedDirectoryPath, currentDirectory, title, importInformation) if err != nil { p.errors <- *err return "" } } else { // Otherwise, we walk upward from the current directory to the imported directory. err := p.verifyNoVCSBoundaryCross(currentDirectory, importedDirectoryPath, title, importInformation) if err != nil { p.errors <- *err return "" } } } // Push the imported path. if isSourceFile { return p.pushPath(pathSourceFile, handler.Kind(), filePath, importInformation.SourceLocation) } else { return p.pushPath(pathLocalPackage, handler.Kind(), dirPath, importInformation.SourceLocation) } } }
// verifyNoVCSBoundaryCross does a check to ensure that walking from the given start path // to the given end path does not cross a VCS boundary. If it does, an error is returned. func (p *PackageLoader) verifyNoVCSBoundaryCross(startPath string, endPath string, title string, importInformation PackageImport) *compilercommon.SourceError { var checkPath = startPath for { if checkPath == endPath { return nil } if vcs.IsVCSRootDirectory(checkPath) { err := compilercommon.SourceErrorf(importInformation.SourceLocation, "Import of %s '%s' crosses VCS boundary at package '%s'", title, importInformation.Path, checkPath) return &err } nextPath := path.Dir(checkPath) if checkPath == nextPath { return nil } checkPath = nextPath } }
func (trr *TypeReferenceResolver) resolveTypeRef(typeref srg.SRGTypeRef, tdg *typegraph.TypeGraph) (typegraph.TypeReference, error) { switch typeref.RefKind() { case srg.TypeRefVoid: return tdg.VoidTypeReference(), nil case srg.TypeRefAny: return tdg.AnyTypeReference(), nil case srg.TypeRefStruct: return tdg.StructTypeReference(), nil case srg.TypeRefMapping: innerType, err := trr.ResolveTypeRef(typeref.InnerReference(), tdg) if err != nil { return tdg.AnyTypeReference(), err } return tdg.NewTypeReference(tdg.MappingType(), innerType), nil case srg.TypeRefSlice: innerType, err := trr.ResolveTypeRef(typeref.InnerReference(), tdg) if err != nil { return tdg.AnyTypeReference(), err } return tdg.NewTypeReference(tdg.SliceType(), innerType), nil case srg.TypeRefStream: innerType, err := trr.ResolveTypeRef(typeref.InnerReference(), tdg) if err != nil { return tdg.AnyTypeReference(), err } return tdg.NewTypeReference(tdg.StreamType(), innerType), nil case srg.TypeRefNullable: innerType, err := trr.ResolveTypeRef(typeref.InnerReference(), tdg) if err != nil { return tdg.AnyTypeReference(), err } return innerType.AsNullable(), nil case srg.TypeRefPath: // Resolve the package type for the type ref. resolvedTypeInfo, found := typeref.ResolveType() if !found { sourceError := compilercommon.SourceErrorf(typeref.Location(), "Type '%s' could not be found", typeref.ResolutionPath()) return tdg.AnyTypeReference(), sourceError } // If the type information refers to an SRG type or generic, find the node directly // in the type graph. var constructedRef = tdg.AnyTypeReference() if !resolvedTypeInfo.IsExternalPackage { // Get the type in the type graph. resolvedType, hasResolvedType := tdg.GetTypeForSourceNode(resolvedTypeInfo.ResolvedType.Node()) if !hasResolvedType { panic(fmt.Sprintf("Could not find typegraph type for SRG type %v", resolvedTypeInfo.ResolvedType.Name())) } constructedRef = tdg.NewTypeReference(resolvedType) } else { // Otherwise, we search for the type in the type graph based on the package from which it // was imported. resolvedType, hasResolvedType := tdg.ResolveTypeUnderPackage(resolvedTypeInfo.ExternalPackageTypePath, resolvedTypeInfo.ExternalPackage) if !hasResolvedType { sourceError := compilercommon.SourceErrorf(typeref.Location(), "Type '%s' could not be found", typeref.ResolutionPath()) return tdg.AnyTypeReference(), sourceError } constructedRef = tdg.NewTypeReference(resolvedType) } // Add the generics. if typeref.HasGenerics() { for _, srgGeneric := range typeref.Generics() { genericTypeRef, err := trr.ResolveTypeRef(srgGeneric, tdg) if err != nil { return tdg.AnyTypeReference(), err } constructedRef = constructedRef.WithGeneric(genericTypeRef) } } // Add the parameters. if typeref.HasParameters() { for _, srgParameter := range typeref.Parameters() { parameterTypeRef, err := trr.ResolveTypeRef(srgParameter, tdg) if err != nil { return tdg.AnyTypeReference(), err } constructedRef = constructedRef.WithParameter(parameterTypeRef) } } return constructedRef, nil default: panic(fmt.Sprintf("Unknown kind of SRG type ref: %v", typeref.RefKind())) return tdg.AnyTypeReference(), nil } }