Example #1
0
// Parses each of the given .mojom files and all of the files in the
// import graph rooted by each file. A single MojomDescriptor is created and
// populated with the result of parsing all of those files. If the parsing is
// successful then err will be nil.
//
// fileNames must not be nil or we will panic.
func (d *ParseDriver) ParseFiles(fileNames []string) (descriptor *mojom.MojomDescriptor, err error) {
	if fileNames == nil {
		// We panic instead of returning an error here because this would be a programming error
		// as opposed to an error in the input.
		panic("fileNames may not be nil.")
	}
	filesToProcess := make([]*FileReference, len(fileNames))
	descriptor = mojom.NewMojomDescriptor()
	for i, fileName := range fileNames {
		filesToProcess[i] = &FileReference{specifiedPath: fileName}
	}

	for len(filesToProcess) > 0 {
		currentFile := filesToProcess[0]
		filesToProcess = filesToProcess[1:]
		if err = d.fileProvider.findFile(currentFile); err != nil {
			return
		}

		var importedFrom *mojom.MojomFile = nil
		if currentFile.importedFrom != nil {
			importedFrom = currentFile.importedFrom.mojomFile
			// Tell the importing file about the absolute path of the imported file.
			// Note that we must do this even if the imported file has already been processed
			// because a given file may be imported by multiple files and each of those need
			// to be told about the absolute path of the imported file.
			importedFrom.SetCanonicalImportName(currentFile.specifiedPath, currentFile.absolutePath)
		}

		if !descriptor.ContainsFile(currentFile.absolutePath) {
			contents, fileReadError := d.fileProvider.provideContents(currentFile)
			if fileReadError != nil {
				err = fileReadError
				return
			}
			// topLevelFileName should be non-empty if and only if the current file is a top-level file.
			topLevelFileName := ""
			if importedFrom == nil {
				topLevelFileName = currentFile.specifiedPath
			}
			parser := MakeParser(currentFile.absolutePath, topLevelFileName,
				contents, descriptor, importedFrom)
			parser.SetDebugMode(d.debugMode)
			// Invoke parser.Parse() (but skip doing so in tests sometimes.)
			d.parseInvoker.invokeParse(&parser)

			if d.debugMode {
				fmt.Printf("\nParseTree for %s:", currentFile)
				fmt.Println(parser.GetParseTree())
			}

			if !parser.OK() {
				err = parser.GetError()
				return
			}
			currentFile.mojomFile = d.fileExtractor.extractMojomFile(&parser)
			for _, importedFile := range currentFile.mojomFile.Imports {
				// Note that it is important that we append all of the imported files here even
				// if some of them have already been processed. That is because when the imported
				// file is pulled from the queue it will be pre-processed during which time the
				// absolute path to the file will be discovered and this absolute path will be
				// set in |mojomFile| which is necessary for serializing mojomFile.
				filesToProcess = append(filesToProcess,
					&FileReference{importedFrom: currentFile, specifiedPath: importedFile.SpecifiedName})
			}
		}
	}

	// Perform type and value resolution
	if err = descriptor.Resolve(); err != nil {
		return
	}

	// Compute enum value integers.
	if err = descriptor.ComputeEnumValueIntegers(); err != nil {
		return
	}

	// Compute data for generators.
	err = descriptor.ComputeDataForGenerators()
	return
}