X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fjagi%2Ffs%2FCompiler.java;h=b277e003274b42d08b415ff52222d30d54c61199;hb=54de0442296cdb195759d1f3ed56f77f77348bf0;hp=14b3786d817ff6e82c15e99045d2c5402ccfb0af;hpb=e8892ea03fb37d1f1d362ad82b16a14986c5cd25;p=jagi.git diff --git a/src/jagi/fs/Compiler.java b/src/jagi/fs/Compiler.java index 14b3786..b277e00 100644 --- a/src/jagi/fs/Compiler.java +++ b/src/jagi/fs/Compiler.java @@ -3,12 +3,52 @@ package jagi.fs; import jagi.*; import java.util.*; import java.util.regex.*; +import java.util.logging.*; import java.nio.file.*; import java.nio.file.attribute.*; import java.io.*; +import java.net.*; public class Compiler { + private static final Logger log = Logger.getLogger("jagi-fs"); private final Map files = new HashMap<>(); + private final Map libs = new HashMap<>(); + private final Collection searchpath = new ArrayList<>(); + + public Compiler() { + String syspath = System.getenv("PATH"); + if(syspath != null) { + String sep = java.io.File.pathSeparator; + int p1 = 0, p2 = syspath.indexOf(sep); + do { + String el; + if(p2 >= 0) { + el = syspath.substring(p1, p2); + p1 = p2 + sep.length(); + p2 = syspath.indexOf(sep, p1); + } else { + el =syspath.substring(p1); + } + try { + Path p = Paths.get(el); + if(p.getParent() != null) + searchpath.add(p.getParent().resolve("share").resolve("java")); + } catch(InvalidPathException e) { + continue; + } + } while(p2 >= 0); + } + String proppath = System.getProperty("jagi.search-path"); + if(proppath != null) { + for(String el : proppath.split(":")) { + try { + searchpath.add(Paths.get(el)); + } catch(InvalidPathException e) { + continue; + } + } + } + } public static class ClassOutput { public final String name; @@ -46,8 +86,9 @@ public class Compiler { } public static class Compilation implements AutoCloseable { - private final Path dir, srcdir, outdir; + public final Path dir, srcdir, outdir; private final List infiles = new ArrayList<>(); + private final List classpath = new ArrayList<>(); private List output = null; public Compilation() throws IOException { @@ -62,11 +103,25 @@ public class Compiler { infiles.add(p); } + public void classpath(Path p) { + classpath.add(p); + } + public boolean compile() throws IOException { List args = new ArrayList<>(); args.add("javac"); args.add("-d"); args.add(outdir.toString()); + if(!classpath.isEmpty()) { + StringBuilder buf = new StringBuilder(); + for(Path cp : classpath) { + if(buf.length() > 0) + buf.append(":"); + buf.append(cp.toString()); + } + args.add("-cp"); + args.add(buf.toString()); + } for(Path p : infiles) args.add(p.toString()); ProcessBuilder cmd = new ProcessBuilder(args); @@ -134,7 +189,8 @@ public class Compiler { public static class BufferedClassLoader extends ClassLoader { public final Map contents; - public BufferedClassLoader(Collection contents) { + public BufferedClassLoader(ClassLoader parent, Collection contents) { + super(parent); this.contents = new HashMap<>(); for(ClassOutput clc : contents) this.contents.put(clc.name, clc.buf.toByteArray()); @@ -148,27 +204,92 @@ public class Compiler { } } - public static class Module { + public static class LibClassLoader extends ClassLoader { + private final ClassLoader[] classpath; + + public LibClassLoader(ClassLoader parent, Collection classpath) { + super(parent); + this.classpath = classpath.toArray(new ClassLoader[0]); + } + + public Class findClass(String name) throws ClassNotFoundException { + for(ClassLoader lib : classpath) { + try { + return(lib.loadClass(name)); + } catch(ClassNotFoundException e) {} + } + throw(new ClassNotFoundException("Could not find " + name + " in any of " + Arrays.asList(classpath).toString())); + } + } + + public ClassLoader libloader(Path p) { + synchronized(libs) { + ClassLoader ret = libs.get(p); + if(ret == null) { + try { + libs.put(p, ret = new URLClassLoader(new URL[] {p.toUri().toURL()})); + } catch(MalformedURLException e) { + throw(new RuntimeException(e)); + } + } + return(ret); + } + } + + private Path findlib(String nm) { + try { + Path p = Paths.get(nm); + if(Files.isRegularFile(p)) + return(p); + } catch(InvalidPathException e) { + } + for(Path dir : searchpath) { + Path jar = dir.resolve(nm + ".jar"); + if(Files.isRegularFile(jar)) + return(jar); + } + return(null); + } + + private static final Pattern classpat = Pattern.compile("^((public|abstract)\\s+)*(class|interface)\\s+(\\S+)"); + private static final Pattern libpat = Pattern.compile("\\$use\\s*:\\s*(\\S+)"); + public class Module { public final Path file; public final ClassLoader code; + public final Collection classpath = new ArrayList<>(); public Module(Path file) throws IOException { this.file = file; try(Compilation c = new Compilation()) { split(c); + for(Path cp : classpath) + c.classpath(cp); if(!c.compile()) throw(new CompilationException(file, c.output())); - code = new BufferedClassLoader(c.classes()); + ClassLoader parent = Compiler.class.getClassLoader(); + if(!classpath.isEmpty()) { + Collection libs = new ArrayList<>(); + for(Path cp : classpath) + libs.add(libloader(cp)); + parent = new LibClassLoader(parent, libs); + } + code = new BufferedClassLoader(parent, c.classes()); } } - private static final Pattern classpat = Pattern.compile("^((public|abstract)\\s+)*(class|interface)\\s+(\\S+)"); public void split(Compilation c) throws IOException { StringBuilder head = new StringBuilder(); BufferedWriter cur = null; try(BufferedReader fp = Files.newBufferedReader(file)) { for(String ln = fp.readLine(); ln != null; ln = fp.readLine()) { - Matcher m = classpat.matcher(ln); + Matcher m = libpat.matcher(ln); + if(m.find()) { + Path lib = findlib(m.group(1)); + if(lib == null) + throw(new CompilationException(file, Arrays.asList("no such library: " + m.group(1)))); + classpath.add(lib); + } + m = classpat.matcher(ln); if(m.find()) { String clnm = m.group(4); Path sp = c.srcdir.resolve(clnm + ".java"); @@ -191,7 +312,7 @@ public class Compiler { } } - public static class File { + public class File { public final Path name; private FileTime mtime = null; private Module mod = null; @@ -204,8 +325,16 @@ public class Compiler { synchronized(this) { FileTime mtime = Files.getLastModifiedTime(name); if((this.mtime == null) || (this.mtime.compareTo(mtime) < 0)) { - mod = new Module(name); + Module pmod = this.mod; + this.mod = new Module(name); this.mtime = mtime; + if(pmod instanceof AutoCloseable) { + try { + ((AutoCloseable)pmod).close(); + } catch(Exception e) { + log.log(Level.WARNING, String.format("Error when disposing updated module %s", pmod.file), e); + } + } } } }