+package org.simantics.graph.compiler.internal.parsing;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.procedure.TObjectIntProcedure;\r
+import gnu.trove.procedure.TObjectObjectProcedure;\r
+\r
+import java.io.ByteArrayOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.PrintStream;\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.Comparator;\r
+import java.util.concurrent.Callable;\r
+import java.util.concurrent.Future;\r
+\r
+import org.antlr.runtime.ANTLRStringStream;\r
+import org.antlr.runtime.CharStream;\r
+import org.antlr.runtime.CommonTokenStream;\r
+import org.antlr.runtime.RecognitionException;\r
+import org.antlr.runtime.TokenStream;\r
+import org.antlr.runtime.tree.Tree;\r
+import org.simantics.graph.compiler.SourceInfo.SourceFile;\r
+import org.simantics.graph.compiler.SourceInfo.Variable;\r
+import org.simantics.graph.compiler.internal.parsing.GraphParser.file_return;\r
+import org.simantics.graph.compiler.internal.parsing.SourceSplitter.SplitPoint;\r
+import org.simantics.graph.compiler.internal.store.VariableStore;\r
+import org.simantics.graph.compiler.internal.translation.GraphTranslator;\r
+import org.simantics.graph.query.Paths;\r
+import org.simantics.graph.store.GraphStore;\r
+import org.simantics.graph.utils.GraphExecutor;\r
+import org.simantics.ltk.ISource;\r
+import org.simantics.ltk.Location;\r
+import org.simantics.ltk.Problem;\r
+import org.simantics.ltk.SourcePart;\r
+import org.simantics.ltk.antlr.ANTLRUtils;\r
+\r
+public class Parsing implements Runnable {\r
+\r
+ Collection<ISource> sources;\r
+ Collection<Problem> errors;\r
+ GraphStore store;\r
+ Paths paths;\r
+ \r
+ public Parsing(Paths paths, Collection<ISource> sources, Collection<Problem> errors,\r
+ GraphStore store) {\r
+ this.paths = paths;\r
+ this.sources = sources;\r
+ this.errors = errors;\r
+ this.store = store;\r
+ }\r
+\r
+ private static class ParsingResult {\r
+ ISource source;\r
+ Tree tree;\r
+ \r
+ public ParsingResult(ISource source, Tree tree) {\r
+ this.source = source;\r
+ this.tree = tree;\r
+ }\r
+ }\r
+ \r
+ public static byte[] read(ISource source) throws IOException {\r
+ int length = source.length();\r
+ if(length >= 0) {\r
+ byte[] buffer = new byte[length];\r
+ InputStream stream = source.open();\r
+ int pos = 0;\r
+ while(pos < buffer.length) {\r
+ int c = stream.read(buffer, pos, buffer.length-pos);\r
+ if(c <= 0)\r
+ break;\r
+ pos += c;\r
+ } \r
+ stream.close(); \r
+ return buffer;\r
+ }\r
+ else {\r
+ byte[] buffer = new byte[1024];\r
+ InputStream stream = source.open();\r
+ int pos = 0;\r
+ while(true) {\r
+ int count = stream.read(buffer, pos, buffer.length-pos);\r
+ if(count <= 0)\r
+ break;\r
+ pos += count;\r
+ if(pos == buffer.length)\r
+ buffer = Arrays.copyOf(buffer, buffer.length*2);\r
+ }\r
+ stream.close();\r
+ if(pos < buffer.length)\r
+ buffer = Arrays.copyOf(buffer, pos);\r
+ return buffer;\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void run() {\r
+ try {\r
+ ArrayList<ISource> orderedSources = \r
+ new ArrayList<ISource>(sources);\r
+ Collections.sort(orderedSources, new Comparator<ISource>() {\r
+ @Override\r
+ public int compare(ISource o1, ISource o2) {\r
+ return o1.getName().compareTo(o2.getName());\r
+ }\r
+ });\r
+ \r
+ ArrayList<Future<ParsingResult>> parsingFutures = new ArrayList<Future<ParsingResult>>(); \r
+ \r
+ //System.out.println("--");\r
+ for(ISource source : orderedSources) {\r
+ String sourceString = new String(read(source), "UTF-8"); \r
+ ArrayList<SplitPoint> splitPoints = SourceSplitter.split(sourceString, 6400); \r
+ //System.out.println(splitPoints.size()-1);\r
+ for(int i=1;i<splitPoints.size();++i) {\r
+ SplitPoint begin = splitPoints.get(i-1);\r
+ SplitPoint end = splitPoints.get(i);\r
+ final String sourcePartString = sourceString.substring(begin.characterId, end.characterId);\r
+ final SourcePart sourcePart = new SourcePart(source, begin.characterId, begin.lineId);\r
+ parsingFutures.add(GraphExecutor.EXECUTOR.submit(new Callable<ParsingResult>() {\r
+ @Override\r
+ public ParsingResult call() throws Exception { \r
+ CharStream stream = new ANTLRStringStream(sourcePartString);\r
+ \r
+ GraphLexer lexer = new GraphLexer(stream) {\r
+ @Override\r
+ public void reportError(RecognitionException e) {\r
+ synchronized(errors) {\r
+ errors.add(ANTLRUtils.error(sourcePart, e, this));\r
+ }\r
+ }\r
+ };\r
+ TokenStream tokenStream = new CommonTokenStream(lexer); \r
+ \r
+ GraphParser parser = new GraphParser(tokenStream) {\r
+ @Override\r
+ public void reportError(RecognitionException e) {\r
+ synchronized(errors) {\r
+ errors.add(ANTLRUtils.error(sourcePart, e, this));\r
+ }\r
+ }\r
+ }; \r
+ \r
+ //long begin = System.nanoTime();\r
+ file_return result = parser.file();\r
+ //long end = System.nanoTime();\r
+ \r
+ if(!errors.isEmpty())\r
+ return null; \r
+ \r
+ /*double time = (end-begin)*1e-6; \r
+ if(time > 200.0) {\r
+ System.out.println(time + " ms, size " + sourcePartString.length());\r
+ System.out.print(sourcePartString);\r
+ }*/\r
+ return new ParsingResult(sourcePart, (Tree)result.getTree());\r
+ }\r
+ }));\r
+ }\r
+ }\r
+ \r
+ /*\r
+ * We want to add graphs to the store in a fixed order and therefore\r
+ * we do not do this part in the same order as the parsing tasks\r
+ * complete.\r
+ */\r
+ THashMap<ISource, GraphTranslator> translators = new THashMap<ISource, GraphTranslator>(); \r
+ for(Future<ParsingResult> future : parsingFutures) { \r
+ ParsingResult result = future.get();\r
+ synchronized(errors) {\r
+ if(!errors.isEmpty())\r
+ continue;\r
+ }\r
+ \r
+ // Translate AST to statements\r
+ //long beginTime = System.nanoTime();\r
+ ISource originalSource = ((SourcePart)result.source).getOriginalSource();\r
+ GraphTranslator translator = translators.get(originalSource);\r
+ if(translator == null) {\r
+ translator = new GraphTranslator(paths, errors, store);\r
+ translators.put(originalSource, translator);\r
+ }\r
+ translator.setSource(result.source);\r
+ translator.translateGraph(result.tree);\r
+ /*long endTime = System.nanoTime();\r
+ reportTime("Trans " + result.source.getName(), beginTime, endTime);\r
+ */\r
+ }\r
+ \r
+ /*for(ISource source : orderedSources) {\r
+ System.out.println(source.getName());\r
+ GraphTranslator translator = translators.get(source);\r
+ translator.getVariables().forEachEntry(new TObjectIntProcedure<String>() { \r
+ @Override\r
+ public boolean execute(String a, int b) {\r
+ System.out.println(" " + a + " " + b);\r
+ return true;\r
+ }\r
+ });\r
+ }*/\r
+ \r
+ final VariableStore variableStore = new VariableStore();\r
+ store.addStore(VariableStore.class, variableStore);\r
+ \r
+ translators.forEachEntry(new TObjectObjectProcedure<ISource, GraphTranslator>() {\r
+ @Override\r
+ public boolean execute(ISource a, GraphTranslator b) {\r
+ final ArrayList<Variable> variables = new ArrayList<Variable>();\r
+ b.getVariables().forEachEntry(new TObjectIntProcedure<String>() {\r
+ @Override\r
+ public boolean execute(String a, int b) {\r
+ variables.add(new Variable(a, b));\r
+ return true;\r
+ }\r
+ });\r
+ variableStore.addSourceFile(\r
+ new SourceFile(a.getName(), \r
+ variables, \r
+ b.getDefinitionPositions()));\r
+ return true;\r
+ }\r
+ });\r
+ } catch(Exception e) {\r
+ e.printStackTrace();\r
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();\r
+ e.printStackTrace(new PrintStream(stream));\r
+ String description = "Internal error: " +\r
+ new String(stream.toByteArray());\r
+ for(ISource source : sources) \r
+ errors.add(new Problem(new Location(source), description));\r
+ }\r
+ }\r
+\r
+}\r