JScratch
Loading...
Searching...
No Matches
CompilerService.java
Go to the documentation of this file.
1package com.jscratch.compiler;
2
3import org.eclipse.jdt.internal.compiler.batch.Main;
4import java.io.*;
5import java.nio.file.*;
6import java.util.*;
7import java.util.regex.Matcher;
8import java.util.regex.Pattern;
9
13public class CompilerService {
14
15 public static CompilationResult compile(String[] sourceCode, String className[], File srcdir, File bindir) {
16 StringWriter outWriter = new StringWriter();
17 StringWriter errWriter = new StringWriter();
18 PrintWriter out = new PrintWriter(outWriter);
19 PrintWriter err = new PrintWriter(errWriter);
20
22 try {
23 if (sourceCode.length != className.length) {
24 throw new RuntimeException("Impossible length mismatch in CompilerService");
25 }
26 // Ensure output directory exists
27 if (!srcdir.exists()) srcdir.mkdirs();
28 if (!bindir.exists()) bindir.mkdirs();
29
30 for (int i = 0; i < className.length; i++) {
31 File sourceFile;
32 if (className[i].contains(".")) {
33 File packagePath = new File(srcdir, className[i].replace('.', '/')).getParentFile();
34 if (!packagePath.exists()) packagePath.mkdirs();
35 sourceFile = new File(packagePath, className[i].substring(className[i].lastIndexOf('.') + 1) + ".java");
36 } else {
37 sourceFile = new File(srcdir, className[i] + ".java");
38 }
39
40 byte[] newBytes = sourceCode[i].getBytes();
41 boolean shouldWrite = true;
42 if (sourceFile.exists()) {
43 try {
44 byte[] oldBytes = Files.readAllBytes(sourceFile.toPath());
45 if (java.util.Arrays.equals(newBytes, oldBytes)) {
46 shouldWrite = false;
47 }
48 } catch (IOException e) {}
49 }
50
51 if (shouldWrite) {
52 Files.write(sourceFile.toPath(), newBytes);
53 }
54 }
55
56 // Setup JDT arguments
57 List<String> args = new ArrayList<>();
58 args.add("-8"); // Target Java 8
59 args.add("-proc:none"); // Disable annotation processing
60 args.add("-cp");
61 args.add(System.getProperty("java.class.path"));
62 args.add("-d");
63 args.add(bindir.getAbsolutePath());
64 args.add(srcdir.getAbsolutePath());
65
66 // Run JDT compiler
67 res.success = Main.compile(args.toArray(new String[0]), out, err, null);
68 out.flush();
69 err.flush();
70
71 res.output = outWriter.toString() + "\n" + errWriter.toString();
72
73 // Parse error output for line numbers
74 // JDT format: 1. ERROR in C:\path\to\File.java (at line 10)
75 Pattern errorPattern = Pattern.compile("^\\d+\\.\\s+ERROR\\s+in\\s+(.*?)\\s+\\(at\\s+line\\s+(\\d+)\\)");
76 BufferedReader reader = new BufferedReader(new StringReader(errWriter.toString()));
77 String line;
78 while ((line = reader.readLine()) != null) {
79 Matcher m = errorPattern.matcher(line);
80 if (m.find()) {
81 String fullPath = m.group(1);
82 String fileName = new File(fullPath).getName();
83 int lineNum = Integer.parseInt(m.group(2));
84
85 // The next 3 lines are code, arrow, and then the message
86 reader.readLine(); // skip code
87 reader.readLine(); // skip arrow
88 String messageLine = reader.readLine();
89 if (messageLine != null) {
90 res.errors.add(new CompilationResult.CompilationError(fileName, lineNum, messageLine.trim()));
91 }
92 }
93 }
94
95 return res;
96 } catch (IOException e) {
97 res.success = false;
98 res.output = e.getMessage();
99 return res;
100 }
101 }
102}
static CompilationResult compile(String[] sourceCode, String className[], File srcdir, File bindir)