-
Notifications
You must be signed in to change notification settings - Fork 26
/
ColCParser.scala
86 lines (74 loc) · 3.27 KB
/
ColCParser.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package vct.parsers
import com.typesafe.scalalogging.LazyLogging
import hre.io.{RWFile, Readable}
import org.antlr.v4.runtime.{CharStream, CharStreams}
import vct.col.origin.{Origin, ReadableOrigin}
import vct.parsers.CParser.PreprocessorError
import vct.parsers.transform.BlameProvider
import vct.result.VerificationError.{Unreachable, UserError}
import java.io.{File, FileNotFoundException, InputStreamReader, OutputStreamWriter, StringWriter}
import java.nio.charset.StandardCharsets
import java.nio.file.{Path, Paths}
case object CParser {
case class PreprocessorError(fileName: String, errorCode: Int, error: String) extends UserError {
override def code: String = "preprocessorError"
override def text: String =
s"Preprocesing file $fileName failed with exit code $errorCode:\n$error"
}
}
case class ColCParser(override val origin: Origin,
override val blameProvider: BlameProvider,
cc: Path,
systemInclude: Path,
otherIncludes: Seq[Path],
defines: Map[String, String]) extends Parser(origin, blameProvider) with LazyLogging {
def interpret(localInclude: Seq[Path], input: String, output: String): Process = {
var command = Seq(cc.toString, "-C", "-E")
command ++= Seq("-nostdinc", "-nocudainc", "-nocudalib", "--cuda-host-only")
command ++= Seq("-isystem", systemInclude.toAbsolutePath.toString)
command ++= localInclude.map("-I" + _.toAbsolutePath)
command ++= otherIncludes.map("-I" + _.toAbsolutePath.toString)
command ++= defines.map { case (k, v) => s"-D$k=$v" }
command ++= Seq("-o", output)
command :+= input
logger.debug(command.toString())
new ProcessBuilder(command:_*).start()
}
override def parse[G](stream: CharStream): ParseResult[G] = {
throw Unreachable("Should not parse C files from an ANTLR CharStream: they need to be interpreted first!")
}
override def parse[G](readable: Readable): ParseResult[G] =
try {
val interpreted = File.createTempFile("vercors-interpreted-", ".i")
interpreted.deleteOnExit()
val process = interpret(
localInclude=Option(Paths.get(readable.fileName).getParent).toSeq,
input="-",
output=interpreted.toString
)
new Thread(() => {
val writer = new OutputStreamWriter(process.getOutputStream, StandardCharsets.UTF_8)
try {
readable.read { reader =>
val written = reader.transferTo(writer)
logger.debug(s"Wrote $written bytes to clang")
}
} finally {
writer.close()
}
}, "[VerCors] clang stdout writer").start()
process.waitFor()
if(process.exitValue() != 0) {
val writer = new StringWriter()
new InputStreamReader(process.getInputStream).transferTo(writer)
new InputStreamReader(process.getErrorStream).transferTo(writer)
writer.close()
throw PreprocessorError(readable.fileName, process.exitValue(), writer.toString)
}
val ireadable = RWFile(interpreted)
val result = ColIParser(Origin(Seq(ReadableOrigin(ireadable))), blameProvider, Some(origin)).parse[G](ireadable)
result
} catch {
case _: FileNotFoundException => throw FileNotFound(readable.fileName)
}
}