Beispiel #1
0
// 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)
}
Beispiel #2
0
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
	}
}
Beispiel #3
0
// 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)
}
Beispiel #4
0
// 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
	}
}
Beispiel #5
0
// 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)
		}
	}
}
Beispiel #6
0
// 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
	}
}
Beispiel #7
0
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
	}
}