From: Fredrik Tolf Date: Wed, 8 Nov 2023 01:38:48 +0000 (+0100) Subject: Rewrite jagidir compiler to call external javac. X-Git-Url: http://git.dolda2000.com/gitweb/?a=commitdiff_plain;h=06577e0b601d42f7d6453d2f4b4fdf70507f4fd6;p=jagi.git Rewrite jagidir compiler to call external javac. --- diff --git a/src/jagi/fs/Compiler.java b/src/jagi/fs/Compiler.java index dcfee03..02c3a7f 100644 --- a/src/jagi/fs/Compiler.java +++ b/src/jagi/fs/Compiler.java @@ -1,51 +1,81 @@ package jagi.fs; +import jagi.*; import java.util.*; import java.util.regex.*; import java.nio.file.*; import java.nio.file.attribute.*; import java.io.*; -import java.net.*; -import javax.tools.*; public class Compiler { private final Map modules = new HashMap<>(); - public static class FilePart extends SimpleJavaFileObject { - public final Path file; - public final String clnm; - public final CharSequence src; + public static class ClassOutput { + public final String name; + public final ByteArrayOutputStream buf = new ByteArrayOutputStream(); - private static URI dummyuri(Path file, String clnm) { - String clp = clnm.replace('.', '/') + Kind.SOURCE.extension; - return(URI.create(file.toUri().toString() + "!/" + clp)); + public ClassOutput(String name) { + this.name = name; } + } - public FilePart(Path file, String clnm, CharSequence src) { - super(dummyuri(file, clnm), Kind.SOURCE); + public static class CompilationException extends RuntimeException { + public final Path file; + private final List messages; + + public CompilationException(Path file, List messages) { this.file = file; - this.clnm = clnm; - this.src = src; + this.messages = messages; + } + + public String getMessage() { + return(file + ": compilation failed"); + } + + public String messages() { + StringBuilder buf = new StringBuilder(); + for(Object msg : messages) + buf.append(msg.toString() + "\n"); + return(buf.toString()); } - public CharSequence getCharContent(boolean ice) { - return(src); + public void printStackTrace(PrintStream out) { + out.print(messages()); + super.printStackTrace(out); + } + } + + public static class Compilation implements AutoCloseable { + private final Path dir, srcdir, outdir; + private final List infiles = new ArrayList<>(); + private List output = null; + + public Compilation() throws IOException { + dir = Files.createTempDirectory("javac"); + srcdir = dir.resolve("src"); + outdir = dir.resolve("out"); + Files.createDirectory(srcdir); + Files.createDirectory(outdir); + } + + public void add(Path p) { + infiles.add(p); } private static final Pattern classpat = Pattern.compile("^((public|abstract)\\s+)*(class|interface)\\s+(\\S+)"); - public static Collection split(Path file) throws IOException { - Collection ret = new ArrayList<>(); + public void split(Path infile) throws IOException { StringBuilder head = new StringBuilder(); - StringBuilder cur = null; - String clnm = null; - try(BufferedReader fp = Files.newBufferedReader(file)) { + BufferedWriter cur = null; + try(BufferedReader fp = Files.newBufferedReader(infile)) { for(String ln = fp.readLine(); ln != null; ln = fp.readLine()) { Matcher m = classpat.matcher(ln); if(m.find()) { + String clnm = m.group(4); + Path sp = srcdir.resolve(clnm + ".java"); + add(sp); if(cur != null) - ret.add(new FilePart(file, clnm, cur)); - clnm = m.group(4); - cur = new StringBuilder(); + cur.close(); + cur = Files.newBufferedWriter(sp); cur.append(head); } if(cur != null) { @@ -54,80 +84,88 @@ public class Compiler { head.append(ln); head.append('\n'); } } + } finally { if(cur != null) - ret.add(new FilePart(file, clnm, cur)); + cur.close(); } - return(ret); - } - } - - public static class ClassOutput extends SimpleJavaFileObject { - public final String name; - private final ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - public ClassOutput(String name) { - super(URI.create("mem://" + name), Kind.CLASS); - this.name = name; - } - - public OutputStream openOutputStream() { - return(buf); - } - } - - public static class FileContext extends ForwardingJavaFileManager { - public final Collection output = new ArrayList<>(); - - public FileContext(JavaCompiler javac) { - super(javac.getStandardFileManager(null, null, null)); - } - - public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) { - ClassOutput cl = new ClassOutput(name); - output.add(cl); - return(cl); - } - } - - public static class CompilationException extends RuntimeException { - public final Path file; - private final List> messages; - - public CompilationException(Path file, List> messages) { - this.file = file; - this.messages = messages; } - public String getMessage() { - return(file + ": compilation failed"); + public boolean compile() throws IOException { + List args = new ArrayList<>(); + args.add("javac"); + args.add("-d"); + args.add(outdir.toString()); + for(Path p : infiles) + args.add(p.toString()); + ProcessBuilder cmd = new ProcessBuilder(args); + cmd.redirectErrorStream(true); + cmd.redirectOutput(ProcessBuilder.Redirect.PIPE); + Process proc = cmd.start(); + List output = new ArrayList<>(); + BufferedReader fp = new BufferedReader(new InputStreamReader(proc.getInputStream(), Utils.UTF8)); + while(true) { + String ln = fp.readLine(); + if(ln == null) + break; + output.add(ln); + } + int status; + try { + status = proc.waitFor(); + } catch(InterruptedException e) { + Thread.currentThread().interrupt(); + throw(new IOException("compilation interrupted")); + } + this.output = output; + return(status == 0); + } + + public List output() { + if(output == null) + throw(new IllegalStateException()); + return(output); + } + + public Collection classes() throws IOException { + Collection ret = new ArrayList<>(); + for(Path p : (Iterable)Files.walk(outdir)::iterator) { + Path rel = outdir.relativize(p); + String fn = rel.getName(rel.getNameCount() - 1).toString(); + if(!Files.isRegularFile(p) || !fn.endsWith(".class")) + continue; + StringBuilder clnm = new StringBuilder(); + for(int i = 0; i < rel.getNameCount() - 1; i++) { + clnm.append(rel.getName(i)); + clnm.append('.'); + } + clnm.append(fn.substring(0, fn.length() - 6)); + ClassOutput cls = new ClassOutput(clnm.toString()); + Files.copy(p, cls.buf); + ret.add(cls); + } + return(ret); } - public String messages() { - StringBuilder buf = new StringBuilder(); - for(Diagnostic msg : messages) - buf.append(msg.toString() + "\n"); - return(buf.toString()); + private static void remove(Path p) throws IOException { + if(Files.isDirectory(p)) { + for(Path ent : (Iterable)Files.list(p)::iterator) + remove(ent); + } + Files.delete(p); } - public void printStackTrace(PrintStream out) { - out.print(messages()); - super.printStackTrace(out); + public void close() throws IOException { + remove(dir); } } public static Collection compile(Path file) throws IOException { - List opt = Arrays.asList(); - JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); - if(javac == null) - throw(new RuntimeException("no javac present")); - Collection files; - files = FilePart.split(file); - DiagnosticCollector out = new DiagnosticCollector<>(); - FileContext fs = new FileContext(javac); - JavaCompiler.CompilationTask job = javac.getTask(null, fs, out, opt, null, files); - if(!job.call()) - throw(new CompilationException(file, out.getDiagnostics())); - return(fs.output); + try(Compilation c = new Compilation()) { + c.split(file); + if(!c.compile()) + throw(new CompilationException(file, c.output())); + return(c.classes()); + } } public static class BufferedClassLoader extends ClassLoader {