OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library source_map_builder; | 5 library source_map_builder; |
6 | 6 |
7 import 'util/util.dart'; | 7 import 'util/util.dart'; |
8 import 'scanner/scannerlib.dart' show Token; | 8 import 'scanner/scannerlib.dart' show Token; |
9 import 'source_file.dart'; | 9 import 'source_file.dart'; |
10 import 'util/uri_extras.dart' show relativize; | 10 import 'util/uri_extras.dart' show relativize; |
11 | 11 |
12 class SourceMapBuilder { | 12 class SourceMapBuilder { |
13 static const int VLQ_BASE_SHIFT = 5; | 13 static const int VLQ_BASE_SHIFT = 5; |
14 static const int VLQ_BASE_MASK = (1 << 5) - 1; | 14 static const int VLQ_BASE_MASK = (1 << 5) - 1; |
15 static const int VLQ_CONTINUATION_BIT = 1 << 5; | 15 static const int VLQ_CONTINUATION_BIT = 1 << 5; |
16 static const int VLQ_CONTINUATION_MASK = 1 << 5; | 16 static const int VLQ_CONTINUATION_MASK = 1 << 5; |
17 static const String BASE64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn' | 17 static const String BASE64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn' |
18 'opqrstuvwxyz0123456789+/'; | 18 'opqrstuvwxyz0123456789+/'; |
19 | 19 |
20 final Uri uri; | 20 final Uri uri; |
21 final Uri fileUri; | 21 final Uri fileUri; |
22 | 22 |
| 23 SourceFile targetFile; |
23 List<SourceMapEntry> entries; | 24 List<SourceMapEntry> entries; |
24 | 25 |
25 Map<String, int> sourceUrlMap; | 26 Map<String, int> sourceUrlMap; |
26 List<String> sourceUrlList; | 27 List<String> sourceUrlList; |
27 Map<String, int> sourceNameMap; | 28 Map<String, int> sourceNameMap; |
28 List<String> sourceNameList; | 29 List<String> sourceNameList; |
29 | 30 |
30 int previousTargetLine; | 31 int previousTargetLine; |
31 int previousTargetColumn; | 32 int previousTargetColumn; |
32 int previousSourceUrlIndex; | 33 int previousSourceUrlIndex; |
33 int previousSourceLine; | 34 int previousSourceLine; |
34 int previousSourceColumn; | 35 int previousSourceColumn; |
35 int previousSourceNameIndex; | 36 int previousSourceNameIndex; |
36 bool firstEntryInLine; | 37 bool firstEntryInLine; |
37 | 38 |
38 SourceMapBuilder(this.uri, this.fileUri) { | 39 SourceMapBuilder(this.uri, this.fileUri, this.targetFile) { |
39 entries = new List<SourceMapEntry>(); | 40 entries = new List<SourceMapEntry>(); |
40 | 41 |
41 sourceUrlMap = new Map<String, int>(); | 42 sourceUrlMap = new Map<String, int>(); |
42 sourceUrlList = new List<String>(); | 43 sourceUrlList = new List<String>(); |
43 sourceNameMap = new Map<String, int>(); | 44 sourceNameMap = new Map<String, int>(); |
44 sourceNameList = new List<String>(); | 45 sourceNameList = new List<String>(); |
45 | 46 |
46 previousTargetLine = 0; | 47 previousTargetLine = 0; |
47 previousTargetColumn = 0; | 48 previousTargetColumn = 0; |
48 previousSourceUrlIndex = 0; | 49 previousSourceUrlIndex = 0; |
49 previousSourceLine = 0; | 50 previousSourceLine = 0; |
50 previousSourceColumn = 0; | 51 previousSourceColumn = 0; |
51 previousSourceNameIndex = 0; | 52 previousSourceNameIndex = 0; |
52 firstEntryInLine = true; | 53 firstEntryInLine = true; |
53 } | 54 } |
54 | 55 |
| 56 resetPreviousSourceLocation() { |
| 57 previousSourceUrlIndex = 0; |
| 58 previousSourceLine = 0; |
| 59 previousSourceColumn = 0; |
| 60 previousSourceNameIndex = 0; |
| 61 } |
| 62 |
| 63 updatePreviousSourceLocation(SourceFileLocation sourceLocation) { |
| 64 previousSourceLine = sourceLocation.getLine(); |
| 65 previousSourceColumn = sourceLocation.getColumn(); |
| 66 String sourceUrl = sourceLocation.getSourceUrl(); |
| 67 previousSourceUrlIndex = indexOf(sourceUrlList, sourceUrl, sourceUrlMap); |
| 68 String sourceName = sourceLocation.getSourceName(); |
| 69 if (sourceName != null) { |
| 70 previousSourceNameIndex = |
| 71 indexOf(sourceNameList, sourceName, sourceNameMap); |
| 72 } |
| 73 } |
| 74 |
| 75 bool sameAsPreviousLocation(SourceFileLocation sourceLocation) { |
| 76 if (sourceLocation == null) { |
| 77 return true; |
| 78 } |
| 79 int sourceUrlIndex = |
| 80 indexOf(sourceUrlList, sourceLocation.getSourceUrl(), sourceUrlMap); |
| 81 return |
| 82 sourceUrlIndex == previousSourceUrlIndex && |
| 83 sourceLocation.getLine() == previousSourceLine && |
| 84 sourceLocation.getColumn() == previousSourceColumn; |
| 85 } |
| 86 |
55 void addMapping(int targetOffset, SourceFileLocation sourceLocation) { | 87 void addMapping(int targetOffset, SourceFileLocation sourceLocation) { |
| 88 |
| 89 bool sameLine(int position, otherPosition) { |
| 90 return targetFile.getLine(position) == targetFile.getLine(otherPosition); |
| 91 } |
| 92 |
| 93 if (!entries.isEmpty && sameLine(targetOffset, entries.last.targetOffset)) { |
| 94 if (sameAsPreviousLocation(sourceLocation)) { |
| 95 // The entry points to the same source location as the previous entry in |
| 96 // the same line, hence it is not needed for the source map. |
| 97 // |
| 98 // TODO(zarah): Remove this check and make sure that [addMapping] is not |
| 99 // called for this position. Instead, when consecutive lines in the |
| 100 // generated code point to the same source location, record this and use |
| 101 // it to generate the entries of the source map. |
| 102 return; |
| 103 } |
| 104 } |
| 105 |
| 106 if (sourceLocation != null) { |
| 107 updatePreviousSourceLocation(sourceLocation); |
| 108 } |
56 entries.add(new SourceMapEntry(sourceLocation, targetOffset)); | 109 entries.add(new SourceMapEntry(sourceLocation, targetOffset)); |
57 } | 110 } |
58 | 111 |
59 void printStringListOn(List<String> strings, StringBuffer buffer) { | 112 void printStringListOn(List<String> strings, StringBuffer buffer) { |
60 bool first = true; | 113 bool first = true; |
61 buffer.write('['); | 114 buffer.write('['); |
62 for (String string in strings) { | 115 for (String string in strings) { |
63 if (!first) buffer.write(','); | 116 if (!first) buffer.write(','); |
64 buffer.write('"'); | 117 buffer.write('"'); |
65 writeJsonEscapedCharsOn(string, buffer); | 118 writeJsonEscapedCharsOn(string, buffer); |
66 buffer.write('"'); | 119 buffer.write('"'); |
67 first = false; | 120 first = false; |
68 } | 121 } |
69 buffer.write(']'); | 122 buffer.write(']'); |
70 } | 123 } |
71 | 124 |
72 String build(SourceFile targetFile) { | 125 String build() { |
| 126 resetPreviousSourceLocation(); |
73 StringBuffer mappingsBuffer = new StringBuffer(); | 127 StringBuffer mappingsBuffer = new StringBuffer(); |
74 entries.forEach((SourceMapEntry entry) => writeEntry(entry, targetFile, | 128 entries.forEach((SourceMapEntry entry) => writeEntry(entry, targetFile, |
75 mappingsBuffer)); | 129 mappingsBuffer)); |
76 StringBuffer buffer = new StringBuffer(); | 130 StringBuffer buffer = new StringBuffer(); |
77 buffer.write('{\n'); | 131 buffer.write('{\n'); |
78 buffer.write(' "version": 3,\n'); | 132 buffer.write(' "version": 3,\n'); |
79 if (uri != null && fileUri != null) { | 133 if (uri != null && fileUri != null) { |
80 buffer.write(' "file": "${relativize(uri, fileUri, false)}",\n'); | 134 buffer.write(' "file": "${relativize(uri, fileUri, false)}",\n'); |
81 } | 135 } |
82 buffer.write(' "sourceRoot": "",\n'); | 136 buffer.write(' "sourceRoot": "",\n'); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 | 174 |
121 if (entry.sourceLocation == null) return; | 175 if (entry.sourceLocation == null) return; |
122 | 176 |
123 String sourceUrl = entry.sourceLocation.getSourceUrl(); | 177 String sourceUrl = entry.sourceLocation.getSourceUrl(); |
124 int sourceLine = entry.sourceLocation.getLine(); | 178 int sourceLine = entry.sourceLocation.getLine(); |
125 int sourceColumn = entry.sourceLocation.getColumn(); | 179 int sourceColumn = entry.sourceLocation.getColumn(); |
126 String sourceName = entry.sourceLocation.getSourceName(); | 180 String sourceName = entry.sourceLocation.getSourceName(); |
127 | 181 |
128 int sourceUrlIndex = indexOf(sourceUrlList, sourceUrl, sourceUrlMap); | 182 int sourceUrlIndex = indexOf(sourceUrlList, sourceUrl, sourceUrlMap); |
129 encodeVLQ(output, sourceUrlIndex - previousSourceUrlIndex); | 183 encodeVLQ(output, sourceUrlIndex - previousSourceUrlIndex); |
130 previousSourceUrlIndex = sourceUrlIndex; | |
131 | |
132 encodeVLQ(output, sourceLine - previousSourceLine); | 184 encodeVLQ(output, sourceLine - previousSourceLine); |
133 previousSourceLine = sourceLine; | |
134 encodeVLQ(output, sourceColumn - previousSourceColumn); | 185 encodeVLQ(output, sourceColumn - previousSourceColumn); |
135 previousSourceColumn = sourceColumn; | 186 updatePreviousSourceLocation(entry.sourceLocation); |
136 | 187 |
137 if (sourceName == null) { | 188 if (sourceName == null) { |
138 return; | 189 return; |
139 } | 190 } |
140 | 191 |
141 int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap); | 192 int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap); |
142 encodeVLQ(output, sourceNameIndex - previousSourceNameIndex); | 193 encodeVLQ(output, sourceNameIndex - previousSourceNameIndex); |
143 previousSourceNameIndex = sourceNameIndex; | 194 |
144 } | 195 } |
145 | 196 |
146 int indexOf(List<String> list, String value, Map<String, int> map) { | 197 int indexOf(List<String> list, String value, Map<String, int> map) { |
147 return map.putIfAbsent(value, () { | 198 return map.putIfAbsent(value, () { |
148 int index = list.length; | 199 int index = list.length; |
149 list.add(value); | 200 list.add(value); |
150 return index; | 201 return index; |
151 }); | 202 }); |
152 } | 203 } |
153 | 204 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 TokenSourceFileLocation(SourceFile sourceFile, this.token) | 258 TokenSourceFileLocation(SourceFile sourceFile, this.token) |
208 : super(sourceFile); | 259 : super(sourceFile); |
209 | 260 |
210 int get offset => token.charOffset; | 261 int get offset => token.charOffset; |
211 | 262 |
212 String getSourceName() { | 263 String getSourceName() { |
213 if (token.isIdentifier()) return token.value; | 264 if (token.isIdentifier()) return token.value; |
214 return null; | 265 return null; |
215 } | 266 } |
216 } | 267 } |
OLD | NEW |