1 package org.simantics.graph.compiler;
3 import java.io.ByteArrayInputStream;
4 import java.io.ByteArrayOutputStream;
5 import java.io.DataInputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.PrintStream;
10 import java.util.ArrayList;
11 import java.util.Collection;
12 import java.util.Formatter;
13 import java.util.Locale;
14 import java.util.TreeMap;
16 import org.simantics.databoard.Bindings;
17 import org.simantics.databoard.Files;
18 import org.simantics.databoard.adapter.AdaptException;
19 import org.simantics.databoard.binding.Binding;
20 import org.simantics.databoard.binding.error.BindingException;
21 import org.simantics.databoard.binding.mutable.Variant;
22 import org.simantics.databoard.container.DataContainer;
23 import org.simantics.databoard.container.DataContainers;
24 import org.simantics.graph.compiler.internal.ltk.FileSource;
25 import org.simantics.graph.compiler.internal.ltk.ISource;
26 import org.simantics.graph.compiler.internal.ltk.Location;
27 import org.simantics.graph.compiler.internal.ltk.Problem;
28 import org.simantics.graph.compiler.internal.parsing.Parsing;
29 import org.simantics.graph.compiler.internal.procedures.AddConsistsOf;
30 import org.simantics.graph.compiler.internal.procedures.ApplyTemplates;
31 import org.simantics.graph.compiler.internal.procedures.Compactify;
32 import org.simantics.graph.compiler.internal.procedures.ConvertPreValues;
33 import org.simantics.graph.compiler.internal.procedures.CreateInverseRelations;
34 import org.simantics.graph.compiler.internal.procedures.CreateTemplates;
35 import org.simantics.graph.compiler.internal.procedures.DefaultValueTyping;
36 import org.simantics.graph.compiler.internal.procedures.MergeEqualResources;
37 import org.simantics.graph.compiler.internal.procedures.PropagateNewMarks;
38 import org.simantics.graph.compiler.internal.resourceFiles.ResourceFileGenerator;
39 import org.simantics.graph.compiler.internal.store.LocationStore;
40 import org.simantics.graph.compiler.internal.store.VariableStore;
41 import org.simantics.graph.compiler.internal.validation.ReportCollisions;
42 import org.simantics.graph.compiler.internal.validation.ValidateGraph;
43 import org.simantics.graph.query.CompositeGraph;
44 import org.simantics.graph.query.Paths;
45 import org.simantics.graph.query.TransferableGraphConversion;
46 import org.simantics.graph.representation.Extensions;
47 import org.simantics.graph.representation.TransferableGraph1;
48 import org.simantics.graph.store.GraphStore;
50 public class GraphCompiler {
52 public static PrintStream out = System.out;
54 public static TransferableGraph1 read(File file) throws Exception {
55 DataContainer container = DataContainers.readFile(file);
56 return (TransferableGraph1)container.content.getValue(TransferableGraph1.BINDING);
59 public static TransferableGraph1 read(InputStream stream) throws AdaptException, IOException {
60 try (InputStream in = stream) {
61 DataContainer container = DataContainers.readFile(new DataInputStream(stream));
62 return (TransferableGraph1)container.content.getValue(TransferableGraph1.BINDING);
66 public static InputStream write(TransferableGraph1 tg) throws BindingException, IOException {
67 Binding binding = TransferableGraph1.BINDING;
68 int hashCode = binding.hashValue(tg);
69 TreeMap<String, Variant> metadata = new TreeMap<>();
70 metadata.put(Extensions.CACHED_HASHCODE, new Variant(Bindings.INTEGER, hashCode));
71 byte[] buffer = DataContainers.writeFile(
72 new DataContainer("graph", 1, metadata, new Variant(binding, tg))
74 return new ByteArrayInputStream(buffer);
77 public static void write(File file, TransferableGraph1 tg) throws BindingException, IOException {
78 Binding binding = TransferableGraph1.BINDING;
79 int hashCode = binding.hashValue(tg);
80 TreeMap<String, Variant> metadata = new TreeMap<>();
81 metadata.put(Extensions.CACHED_HASHCODE, new Variant(Bindings.INTEGER, hashCode));
82 DataContainers.writeFile(file, new DataContainer("graph", 1, metadata, new Variant(binding, tg)));
85 public static CompilationResult compile(
87 Collection<ISource> sources,
88 Collection<TransferableGraph1> dependencies,
89 ExternalFileLoader fileLoader,
90 GraphCompilerPreferences preferences) {
91 //out.println(preferences);
93 Collection<Problem> errors = new ArrayList<Problem>();
94 GraphStore store = new GraphStore();
96 CompilationResult compilationResult = new CompilationResult();
97 compilationResult.errors = errors;
98 compilationResult.warnings = new ArrayList<Problem>();
100 Paths paths = new Paths(Layer0Version);
103 run(new Parsing(paths, sources, errors, store));
105 if(!errors.isEmpty())
106 return compilationResult;
108 // Create composite graph of the new statements and dependencies
109 CompositeGraph graph;
111 long beginTime = System.nanoTime();
112 graph = TransferableGraphConversion.convert(paths, dependencies);
113 graph.addFragment(store);
114 long endTime = System.nanoTime();
115 reportTime("Composition", beginTime, endTime);
119 run(new MergeEqualResources(paths, store));
121 int[] unfoundedIdentitities = store.identities.getUnfoundedIdentities();
122 if(unfoundedIdentitities.length > 0) {
123 LocationStore locations = store.getStore(LocationStore.class);
124 for(int id : unfoundedIdentitities) {
125 errors.add(new Problem(
126 locations.getLocation(id),
127 "URIless resource used as a parent."));
129 return compilationResult;
132 store.identities.createPathToId(paths.ConsistsOf);
133 run(new CreateTemplates(graph, store, errors));
134 run(new ApplyTemplates(graph, store, errors, fileLoader));
135 run(new DefaultValueTyping(paths, store));
136 run(new Compactify(store));
137 run(new PropagateNewMarks(store));
138 run(new CreateInverseRelations(graph, store));
139 run(new AddConsistsOf(paths, store));
140 run(new ConvertPreValues(graph, store, errors));
141 run(new ReportCollisions(preferences, errors, store));
142 if(preferences.validate)
143 run(new ValidateGraph(graph, errors, store, preferences));
147 long beginTime = System.nanoTime();
148 compilationResult.graph = TransferableGraphConversion.convert(graph, store);
149 long endTime = System.nanoTime();
150 reportTime("Generate TG", beginTime, endTime);
153 // Create resource files
155 long beginTime = System.nanoTime();
156 compilationResult.resourceFiles = ResourceFileGenerator.generate(paths, store);
157 long endTime = System.nanoTime();
158 reportTime("Generate resources", beginTime, endTime);
161 // Create source info
163 VariableStore variableStore = store.getStore(VariableStore.class);
164 compilationResult.sourceInfo = variableStore.getSourceInfo();
167 // Fix source location of problems whose location is null at this point
169 for(Problem problem : compilationResult.errors) {
170 if(problem.getLocation() == null)
171 for(ISource source : sources) {
172 problem.setLocation(new Location(source));
175 else if(problem.getLocation().getSource() == null)
176 for(ISource source : sources) {
177 problem.getLocation().setSource(source);
181 for(Problem problem : compilationResult.warnings) {
182 if(problem.getLocation() == null)
183 for(ISource source : sources) {
184 problem.setLocation(new Location(source));
187 else if(problem.getLocation().getSource() == null)
188 for(ISource source : sources) {
189 problem.getLocation().setSource(source);
194 } catch(Exception e) {
196 ByteArrayOutputStream stream = new ByteArrayOutputStream();
197 e.printStackTrace(new PrintStream(stream));
198 String description = "Internal error: " +
199 new String(stream.toByteArray());
200 for(ISource source : sources)
201 errors.add(new Problem(new Location(source), description));
204 return compilationResult;
207 private static void run(Runnable runnable) {
208 //long beginTime = System.nanoTime();
210 //long endTime = System.nanoTime();
212 //reportTime(runnable.getClass().getSimpleName(), beginTime, endTime);
215 public static void reportTime(String taskName, long beginTime, long endTime) {
216 StringBuilder sb = new StringBuilder();
217 @SuppressWarnings("resource")
218 Formatter formatter = new Formatter(sb, Locale.US);
219 formatter.format("%-25s %8.4f ms", taskName, (endTime - beginTime)*1e-6);
221 out.println(sb.toString());
224 public static void reportTime(String taskName, long beginTime) {
225 reportTime(taskName, beginTime, System.nanoTime());
228 public static void main(String[] args) {
229 Collection<ISource> sources = new ArrayList<ISource>();
230 Collection<TransferableGraph1> dependencies = new ArrayList<TransferableGraph1>();
231 String outputFile = null;
233 for(int i=0;i<args.length;++i) {
234 String arg = args[i];
235 if(arg.equals("-o")) {
236 if(++i < args.length)
237 outputFile = args[i];
240 if(arg.endsWith(".tg")) {
242 dependencies.add(read(new File(arg)));
243 } catch (Exception e) {
248 else if(arg.endsWith(".graph") || arg.endsWith(".pgraph")) {
249 sources.add(new FileSource(arg));
252 System.err.println("Invalid input file extension " + arg);
258 if(sources.isEmpty()) {
259 System.err.println("No source files");
263 if(outputFile == null) {
264 System.err.println("Name of the output file is not given (use -o flag).");
268 CompilationResult result = compile("1.0", sources, dependencies, null, new GraphCompilerPreferences());
269 for(Problem problem : result.getErrors())
270 out.println(problem.getLocation() + ": " + problem.getDescription());
272 if(result.getGraph() != null)
274 Files.createFile(new File(outputFile), TransferableGraph1.BINDING, result.getGraph());
275 } catch (Exception e) {