comparison graal/com.oracle.truffle.api/src/com/oracle/truffle/api/source/SourceManager.java @ 13564:35f637594acc

Truffle: refinements in the management of source information: a new marker interface for empty SourceSections and fix a bug that kept modified source files from being reloaded.
author Michael Van De Vanter <michael.van.de.vanter@oracle.com>
date Tue, 07 Jan 2014 18:21:20 -0800
parents f76593e3fedb
children f150a67b99e3
comparison
equal deleted inserted replaced
13563:fb846424299f 13564:35f637594acc
1 /* 1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this 7 * published by the Free Software Foundation. Oracle designates this
45 * </ul> 45 * </ul>
46 */ 46 */
47 public final class SourceManager { 47 public final class SourceManager {
48 48
49 // Only files and fake files are indexed. 49 // Only files and fake files are indexed.
50 private final Map<String, SourceImpl> sourceMap = new HashMap<>(); 50 private final Map<String, SourceImpl> pathToSource = new HashMap<>();
51 51
52 public SourceManager() { 52 public SourceManager() {
53 53
54 } 54 }
55 55
56 /** 56 /**
57 * Gets the canonical representation of a source file, whose contents will be read lazily and 57 * Gets the canonical representation of a source file, whose contents will be read lazily and
58 * then cached. 58 * then cached.
59 * 59 *
60 * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read. 60 * @param reset forces any existing {@link Source} cache to be cleared, forcing a re-read
61 */ 61 */
62 public Source get(String fileName, boolean reset) { 62 public Source get(String fileName, boolean reset) {
63 SourceImpl source = sourceMap.get(fileName); 63
64 SourceImpl source = pathToSource.get(fileName);
64 if (source == null) { 65 if (source == null) {
65 String path = findPath(fileName); 66 final File file = new File(fileName);
66 if (path == null) { 67 String path = null;
67 throw new RuntimeException("Can't find file " + fileName); 68 if (file.exists()) {
68 } 69 try {
69 source = sourceMap.get(path); 70 path = file.getCanonicalPath();
71 } catch (IOException e) {
72 throw new RuntimeException("Can't find file " + fileName);
73 }
74 }
75 source = pathToSource.get(path);
70 if (source == null) { 76 if (source == null) {
71 source = new FileSourceImpl(fileName, path); 77 source = new FileSourceImpl(file, fileName, path);
72 sourceMap.put(path, source); 78 pathToSource.put(path, source);
73 } 79 }
74 } else { 80 }
75 if (reset) { 81 if (reset) {
76 source.reset(); 82 source.reset();
77 }
78 } 83 }
79 return source; 84 return source;
80 } 85 }
81 86
82 /** 87 /**
109 * Creates a source from literal text, but which acts as a file and can be retrieved by name 114 * Creates a source from literal text, but which acts as a file and can be retrieved by name
110 * (unlike other literal sources); intended for testing. 115 * (unlike other literal sources); intended for testing.
111 */ 116 */
112 public Source getFakeFile(String name, String code) { 117 public Source getFakeFile(String name, String code) {
113 final SourceImpl source = new LiteralSourceImpl(name, code); 118 final SourceImpl source = new LiteralSourceImpl(name, code);
114 sourceMap.put(name, source); 119 pathToSource.put(name, source);
115 return source; 120 return source;
116 }
117
118 // If it names a real file, get the (canonical) normalized absolute path.
119 private static String findPath(String name) {
120 final File file = new File(name);
121 if (file.exists()) {
122 try {
123 return file.getCanonicalPath();
124 } catch (IOException e) {
125 }
126 }
127 return null;
128 } 121 }
129 122
130 private static String readCode(Reader reader) throws IOException { 123 private static String readCode(Reader reader) throws IOException {
131 final StringBuilder builder = new StringBuilder(); 124 final StringBuilder builder = new StringBuilder();
132 final char[] buffer = new char[1024]; 125 final char[] buffer = new char[1024];
140 } 133 }
141 134
142 return builder.toString(); 135 return builder.toString();
143 } 136 }
144 137
145 // TODO (mlvdv) make this private once some related code changes propagate 138 private abstract static class SourceImpl implements Source {
146 public abstract static class SourceImpl implements Source {
147 139
148 protected TextMap textMap = null; 140 protected TextMap textMap = null;
149 141
150 protected abstract void reset(); 142 protected abstract void reset();
151 143
265 257
266 } 258 }
267 259
268 private static class FileSourceImpl extends SourceImpl { 260 private static class FileSourceImpl extends SourceImpl {
269 261
262 private final File file;
270 private final String name; // Name used originally to describe the source 263 private final String name; // Name used originally to describe the source
271 private String code = null;
272 private final String path; // Normalized path description of an actual file 264 private final String path; // Normalized path description of an actual file
273 private boolean readAttempted; 265
274 266 private String code = null; // A cache of the file's contents
275 public FileSourceImpl(String name, String path) { 267 private long timeStamp; // timestamp of the cache in the file system
268
269 public FileSourceImpl(File file, String name, String path) {
270 this.file = file;
276 this.name = name; 271 this.name = name;
277 this.path = path; 272 this.path = path;
278 this.readAttempted = false;
279
280 } 273 }
281 274
282 @Override 275 @Override
283 public String getName() { 276 public String getName() {
284 return name; 277 return name;
285 } 278 }
286 279
287 @Override 280 @Override
288 public String getCode() { 281 public String getCode() {
289 if (code == null && !readAttempted) { 282 if (code == null || timeStamp != file.lastModified()) {
290 readAttempted = true;
291 try { 283 try {
292 code = readCode(getReader()); 284 code = readCode(getReader());
285 timeStamp = file.lastModified();
293 } catch (IOException e) { 286 } catch (IOException e) {
294 } 287 }
295 } 288 }
296 return code; 289 return code;
297 } 290 }
301 return path; 294 return path;
302 } 295 }
303 296
304 @Override 297 @Override
305 public Reader getReader() { 298 public Reader getReader() {
306 if (code != null) { 299 if (code != null && timeStamp == file.lastModified()) {
307 return new StringReader(code); 300 return new StringReader(code);
308 } 301 }
309 try { 302 try {
310 return new BufferedReader(new FileReader(path)); 303 return new FileReader(file);
311 } catch (FileNotFoundException e) { 304 } catch (FileNotFoundException e) {
312 throw new RuntimeException("Can't find file " + path); 305 throw new RuntimeException("Can't find file " + path);
313 } 306 }
314 } 307 }
315 308
316 @Override 309 @Override
317 protected void reset() { 310 protected void reset() {
318 this.code = null; 311 this.code = null;
319 this.readAttempted = false;
320 } 312 }
321 313
322 } 314 }
323 315
324 } 316 }