Files
sdk/lib/compiler/implementation/source_map_builder.dart
T
podivilov@google.com b5a251f42c Throw an exception when invalid source file location is encountered.
Currently, compiler is crashed in SourceMapBuilder with unhelpful stack trace.
Throwing an exception in ssa builder will help us to fix crashes that
occur in the wild.

R=ahe@google.com,kasperl@google.com
BUG=5184

Review URL: https://codereview.chromium.org//10970015

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12765 260f80e4-7a28-3924-810f-c04153c831b5
2012-09-24 09:43:53 +00:00

177 lines
5.0 KiB
Dart

// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#library('source_map_builder');
#import('dart:json');
#import('scanner/scannerlib.dart');
#import('source_file.dart');
class SourceMapBuilder {
static const int VLQ_BASE_SHIFT = 5;
static const int VLQ_BASE_MASK = (1 << 5) - 1;
static const int VLQ_CONTINUATION_BIT = 1 << 5;
static const int VLQ_CONTINUATION_MASK = 1 << 5;
static const String BASE64_DIGITS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn'
'opqrstuvwxyz0123456789+/';
List<SourceMapEntry> entries;
Map<String, int> sourceUrlMap;
List<String> sourceUrlList;
Map<String, int> sourceNameMap;
List<String> sourceNameList;
int previousTargetLine;
int previousTargetColumn;
int previousSourceUrlIndex;
int previousSourceLine;
int previousSourceColumn;
int previousSourceNameIndex;
bool firstEntryInLine;
SourceMapBuilder() {
entries = new List<SourceMapEntry>();
sourceUrlMap = new Map<String, int>();
sourceUrlList = new List<String>();
sourceNameMap = new Map<String, int>();
sourceNameList = new List<String>();
previousTargetLine = 0;
previousTargetColumn = 0;
previousSourceUrlIndex = 0;
previousSourceLine = 0;
previousSourceColumn = 0;
previousSourceNameIndex = 0;
firstEntryInLine = true;
}
void addMapping(int targetOffset, SourceFileLocation sourceLocation) {
entries.add(new SourceMapEntry(sourceLocation, targetOffset));
}
String build(SourceFile targetFile) {
StringBuffer buffer = new StringBuffer();
buffer.add('{\n');
buffer.add(' "version": 3,\n');
buffer.add(' "mappings": "');
entries.forEach((SourceMapEntry entry) => writeEntry(entry, targetFile, buffer));
buffer.add('",\n');
buffer.add(' "sources": ');
JSON.printOn(sourceUrlList, buffer);
buffer.add(',\n');
buffer.add(' "names": ');
JSON.printOn(sourceNameList, buffer);
buffer.add('\n}\n');
return buffer.toString();
}
void writeEntry(SourceMapEntry entry, SourceFile targetFile, StringBuffer output) {
int targetLine = targetFile.getLine(entry.targetOffset);
int targetColumn = targetFile.getColumn(targetLine, entry.targetOffset);
if (targetLine > previousTargetLine) {
for (int i = previousTargetLine; i < targetLine; ++i) {
output.add(';');
}
previousTargetLine = targetLine;
previousTargetColumn = 0;
firstEntryInLine = true;
}
if (!firstEntryInLine) {
output.add(',');
}
firstEntryInLine = false;
encodeVLQ(output, targetColumn - previousTargetColumn);
previousTargetColumn = targetColumn;
if (entry.sourceLocation === null) return;
String sourceUrl = entry.sourceLocation.getSourceUrl();
int sourceLine = entry.sourceLocation.getLine();
int sourceColumn = entry.sourceLocation.getColumn();
String sourceName = entry.sourceLocation.getSourceName();
int sourceUrlIndex = indexOf(sourceUrlList, sourceUrl, sourceUrlMap);
encodeVLQ(output, sourceUrlIndex - previousSourceUrlIndex);
previousSourceUrlIndex = sourceUrlIndex;
encodeVLQ(output, sourceLine - previousSourceLine);
previousSourceLine = sourceLine;
encodeVLQ(output, sourceColumn - previousSourceColumn);
previousSourceColumn = sourceColumn;
if (sourceName === null) {
return;
}
int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap);
encodeVLQ(output, sourceNameIndex - previousSourceNameIndex);
previousSourceNameIndex = sourceNameIndex;
}
int indexOf(List<String> list, String value, Map<String, int> map) {
return map.putIfAbsent(value, () {
int index = list.length;
map[value] = index;
list.add(value);
return index;
});
}
static void encodeVLQ(StringBuffer output, int value) {
int signBit = 0;
if (value < 0) {
signBit = 1;
value = -value;
}
value = (value << 1) | signBit;
do {
int digit = value & VLQ_BASE_MASK;
value >>= VLQ_BASE_SHIFT;
if (value > 0) {
digit |= VLQ_CONTINUATION_BIT;
}
output.add(BASE64_DIGITS[digit]);
} while (value > 0);
}
}
class SourceMapEntry {
SourceFileLocation sourceLocation;
int targetOffset;
SourceMapEntry(this.sourceLocation, this.targetOffset);
}
class SourceFileLocation {
SourceFile sourceFile;
Token token;
int line;
SourceFileLocation(this.sourceFile, this.token) {
assert(isValid());
}
String getSourceUrl() => sourceFile.filename;
int getLine() {
if (line == null) line = sourceFile.getLine(token.charOffset);
return line;
}
int getColumn() => sourceFile.getColumn(getLine(), token.charOffset);
String getSourceName() {
if (token.isIdentifier()) return token.slowToString();
return null;
}
bool isValid() => token.charOffset < sourceFile.text.length;
}