blob: 6940d00e7a4821eba004ef5468d567ebb66912c6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File
import scala.collection.mutable.ListBuffer
import scala.io.Source
import scala.util.matching.Regex
class Symbols(
val libraryName: String,
val fileName: String,
val packageName: String,
val exports: List[String]
)
object GenSymbolTable extends App {
val ignoreFiles = List(
"daffodil-runtime1/src/main/scala/org/apache/daffodil/reflection/FieldFinder.scala"
)
val rePackage: Regex = """package ([\w\.]+)""".r
def parsePackageName(lines: Iterator[String]): String = {
for (line <- lines) {
rePackage.findFirstMatchIn(line) match {
case Some(name) => return name.group(1)
case None =>
}
}
throw new Exception("expected package name but not found")
}
val reExports = List(
"^(?:abstract |case |final |sealed |implict |lazy )* ?class ([\\w\\.]+)".r,
"^(?:abstract |case |final |sealed |implict |lazy )* ?object ([\\w\\.]+)".r,
"^(?:abstract |case |final |sealed |implict |lazy )* ?trait ([\\w\\.]+)".r
)
def parseExports(lines: Iterator[String]): List[String] = {
val exports = ListBuffer.empty[String]
for (line <- lines) {
for (regexp <- reExports) {
regexp.findFirstMatchIn(line) match {
case Some(name) => exports += name.group(1)
case None =>
}
}
}
exports.toList
}
val reLineComment = "//.*".r
val reBlockStartComment: Regex = """^.*(\/\*).*$""".r
val reBlockEndComment: Regex = """^.*(\*\/).*$""".r
def cleanFile(file: File): List[String] = {
val cleaned = ListBuffer.empty[String]
val source = Source.fromFile(file)
var inBlockComment = false
var exitingBlockComment = false
for (actual <- source.getLines()) {
exitingBlockComment = false
val line = reLineComment.replaceFirstIn(actual, "")
line match {
case reBlockStartComment(_) => inBlockComment = true
case reBlockEndComment(_) => exitingBlockComment = true
case _ =>
}
if (!inBlockComment) cleaned += line
if (exitingBlockComment) inBlockComment = false
}
source.close
cleaned.toList
}
def processFile(libraryName: String, file: File): Option[Symbols] = {
ignoreFiles.find(file.toString.endsWith(_)) match {
case Some(_) => return None
case _ =>
}
try {
val iter = cleanFile(file).iterator
val packageName = parsePackageName(iter)
val exports = parseExports(iter)
Some(new Symbols(libraryName, file.toString, packageName, exports))
} catch {
case e: Exception => throw new Exception(s"while processing file: $file", e)
}
}
def processDir(libraryName: String, dir: File): List[Symbols] = {
val symbols = ListBuffer.empty[Symbols]
val files = dir.listFiles()
for (file <- files) {
val name = file.getName
if (name.startsWith("Test") || name == "test") {} else if (file.isDirectory)
symbols ++= processDir(libraryName, file)
else if (name.endsWith(".scala") || name.endsWith(".java")) {
processFile(libraryName, file) match {
case Some(s) => symbols += s
case _ =>
}
}
}
symbols.toList
}
def processLibrary(dir: File): List[Symbols] = {
val libraryName = dir.getName
processDir(libraryName, dir)
}
for (arg <- args) {
val libraryDir = new File(arg)
val symbols = processLibrary(libraryDir)
for (symbol <- symbols) {
for (export <- symbol.exports)
println(s"${symbol.libraryName}:${symbol.packageName}.${export}")
}
}
}