Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions lib/src/interpolation_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,14 @@ final class InterpolationMap {

/// Maps [error]'s span in the string generated from this interpolation to its
/// original source.
///
/// Returns [error] if its span is null, or if it's already been mapped.
FormatException mapException(SourceSpanFormatException error) {
var target = error.span;
if (target == null) return error;

if (_interpolation.contents.isEmpty) {
if (_isMapped(target)) return error;
return SourceSpanFormatException(
error.message,
_interpolation.span,
Expand All @@ -57,6 +60,8 @@ final class InterpolationMap {
}

var source = mapSpan(target);
if (identical(source, target)) return error;

var startIndex = _indexInContents(target.start);
var endIndex = _indexInContents(target.end);

Expand All @@ -79,24 +84,36 @@ final class InterpolationMap {

/// Maps a span in the string generated from this interpolation to its
/// original source.
FileSpan mapSpan(SourceSpan target) => switch ((
_mapLocation(target.start),
_mapLocation(target.end),
)) {
(FileSpan start, FileSpan end) => start.expand(end),
(FileSpan start, FileLocation end) => _interpolation.span.file.span(
_expandInterpolationSpanLeft(start.start),
end.offset,
),
(FileLocation start, FileSpan end) => _interpolation.span.file.span(
start.offset,
_expandInterpolationSpanRight(end.end),
),
(FileLocation start, FileLocation end) => _interpolation.span.file.span(
start.offset,
end.offset,
),
_ => throw '[BUG] Unreachable',
///
/// Returns [target] as-is if it's already been mapped.
FileSpan mapSpan(SourceSpan target) {
if (_isMapped(target)) return target as FileSpan;

return switch ((
_mapLocation(target.start),
_mapLocation(target.end),
)) {
(FileSpan start, FileSpan end) => start.expand(end),
(FileSpan start, FileLocation end) => _interpolation.span.file.span(
_expandInterpolationSpanLeft(start.start),
end.offset,
),
(FileLocation start, FileSpan end) => _interpolation.span.file.span(
start.offset,
_expandInterpolationSpanRight(end.end),
),
(FileLocation start, FileLocation end) => _interpolation.span.file.span(
start.offset,
end.offset,
),
_ => throw '[BUG] Unreachable',
};
}

/// Returns whether [span] has already been mapped by this mapper.
bool _isMapped(SourceSpan span) => switch (span) {
FileSpan(:var file) => identical(file, _interpolation.span.file),
_ => false,
};

/// Maps a location in the string generated from this interpolation to its
Expand Down
16 changes: 8 additions & 8 deletions lib/src/parse/css.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CssParser extends ScssParser {
super.silentComment();
error(
"Silent comments aren't allowed in plain CSS.",
scanner.spanFrom(start),
spanFrom(start),
);
}

Expand Down Expand Up @@ -86,7 +86,7 @@ class CssParser extends ScssParser {
/// Throws an error for a forbidden at-rule.
Never _forbiddenAtRule(LineScannerState start) {
almostAnyValue();
error("This at-rule isn't allowed in plain CSS.", scanner.spanFrom(start));
error("This at-rule isn't allowed in plain CSS.", spanFrom(start));
}

/// Consumes a plain-CSS `@import` rule that disallows interpolation.
Expand Down Expand Up @@ -128,8 +128,8 @@ class CssParser extends ScssParser {
var modifiers = tryImportModifiers();
expectStatementSeparator("@import rule");
return ImportRule([
StaticImport(url, scanner.spanFrom(urlStart), modifiers: modifiers),
], scanner.spanFrom(start));
StaticImport(url, spanFrom(urlStart), modifiers: modifiers),
], spanFrom(start));
}

ParenthesizedExpression parentheses() {
Expand All @@ -140,7 +140,7 @@ class CssParser extends ScssParser {
_whitespace();
var expression = expressionUntilComma();
scanner.expectChar($rparen);
return ParenthesizedExpression(expression, scanner.spanFrom(start));
return ParenthesizedExpression(expression, spanFrom(start));
}

Expression identifierLike() {
Expand Down Expand Up @@ -179,14 +179,14 @@ class CssParser extends ScssParser {
if (_disallowedFunctionNames.contains(plain)) {
error(
"This function isn't allowed in plain CSS.",
scanner.spanFrom(start),
spanFrom(start),
);
}

return FunctionExpression(
plain,
ArgumentList(arguments, const {}, scanner.spanFrom(beforeArguments)),
scanner.spanFrom(start),
ArgumentList(arguments, const {}, spanFrom(beforeArguments)),
spanFrom(start),
);
}

Expand Down
19 changes: 16 additions & 3 deletions lib/src/parse/parser.dart
Original file line number Diff line number Diff line change
Expand Up @@ -669,8 +669,18 @@ class Parser {
/// Like [scanner.spanFrom], but passes the span through [_interpolationMap]
/// if it's available.
@protected
FileSpan spanFrom(LineScannerState state) {
var span = scanner.spanFrom(state);
FileSpan spanFrom(LineScannerState start, [LineScannerState? end]) {
var span = scanner.spanFrom(start, end);
return _interpolationMap == null
? span
: LazyFileSpan(() => _interpolationMap.mapSpan(span));
}

/// Like [scanner.spanFromPosition], but passes the span through
/// [_interpolationMap] if it's available.
@protected
FileSpan spanFromPosition(int start, [int? end]) {
var span = scanner.spanFromPosition(start, end);
return _interpolationMap == null
? span
: LazyFileSpan(() => _interpolationMap.mapSpan(span));
Expand Down Expand Up @@ -728,7 +738,10 @@ class Parser {
var map = _interpolationMap;
if (map == null) rethrow;

throwWithTrace(map.mapException(error), error, stackTrace);
var mapped = map.mapException(error);
if (identical(mapped, error)) rethrow;

throwWithTrace(mapped, error, stackTrace);
}
} on MultiSourceSpanFormatException catch (error, stackTrace) {
var span = error.span as FileSpan;
Expand Down
12 changes: 6 additions & 6 deletions lib/src/parse/sass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class SassParser extends StylesheetParser {
} while (buffer.trailingString.trimRight().endsWith(',') &&
scanCharIf((char) => char.isNewline));

return buffer.interpolation(scanner.spanFrom(start));
return buffer.interpolation(spanFrom(start));
}

void expectStatementSeparator([String? name]) {
Expand Down Expand Up @@ -97,7 +97,7 @@ class SassParser extends StylesheetParser {
next = scanner.peekChar();
}
var url = scanner.substring(start.position);
var span = scanner.spanFrom(start);
var span = spanFrom(start);

if (isPlainImportUrl(url)) {
// Serialize [url] as a Sass string because [StaticImport] expects it to
Expand Down Expand Up @@ -218,7 +218,7 @@ class SassParser extends StylesheetParser {

return lastSilentComment = SilentComment(
buffer.toString(),
scanner.spanFrom(start),
spanFrom(start),
);
}

Expand Down Expand Up @@ -269,7 +269,7 @@ class SassParser extends StylesheetParser {
if (scanner.peekChar(1) == $slash) {
buffer.writeCharCode(scanner.readChar());
buffer.writeCharCode(scanner.readChar());
var span = scanner.spanFrom(start);
var span = spanFrom(start);
whitespace(consumeNewlines: false);

// For backwards compatibility, allow additional comments after
Expand All @@ -290,7 +290,7 @@ class SassParser extends StylesheetParser {
}
throw MultiSpanSassFormatException(
"Unexpected text after end of comment",
scanner.spanFrom(errorStart),
spanFrom(errorStart),
"extra text",
{span: "comment"},
);
Expand Down Expand Up @@ -318,7 +318,7 @@ class SassParser extends StylesheetParser {
_readIndentation();
}

return LoudComment(buffer.interpolation(scanner.spanFrom(start)));
return LoudComment(buffer.interpolation(spanFrom(start)));
}

void whitespaceWithoutComments({required bool consumeNewlines}) {
Expand Down
8 changes: 4 additions & 4 deletions lib/src/parse/scss.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class ScssParser extends StylesheetParser {
'versions.\n'
'\n'
'Recommendation: @else if',
span: scanner.spanFrom(beforeAt),
span: spanFrom(beforeAt),
));
scanner.position -= 2;
return true;
Expand Down Expand Up @@ -140,13 +140,13 @@ class ScssParser extends StylesheetParser {
if (plainCss) {
error(
"Silent comments aren't allowed in plain CSS.",
scanner.spanFrom(start),
spanFrom(start),
);
}

return lastSilentComment = SilentComment(
scanner.substring(start.position),
scanner.spanFrom(start),
spanFrom(start),
);
}

Expand All @@ -172,7 +172,7 @@ class ScssParser extends StylesheetParser {
if (scanner.peekChar() != $slash) continue loop;

buffer.writeCharCode(scanner.readChar());
return LoudComment(buffer.interpolation(scanner.spanFrom(start)));
return LoudComment(buffer.interpolation(spanFrom(start)));

case $cr:
scanner.readChar();
Expand Down
21 changes: 8 additions & 13 deletions lib/src/parse/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ class SelectorParser extends Parser {
if (_plainCss) {
error(
"Placeholder selectors aren't allowed in plain CSS.",
scanner.spanFrom(start),
spanFrom(start),
);
}
return selector;
Expand All @@ -247,7 +247,7 @@ class SelectorParser extends Parser {
if (!allowParent) {
error(
"Parent selectors aren't allowed here.",
scanner.spanFrom(start),
spanFrom(start),
);
}
return selector;
Expand Down Expand Up @@ -316,7 +316,7 @@ class SelectorParser extends Parser {

/// Consumes an attribute selector's operator.
AttributeOperator _attributeOperator() {
var start = scanner.state;
var start = scanner.position;
switch (scanner.readChar()) {
case $equal:
return AttributeOperator.equal;
Expand All @@ -342,7 +342,7 @@ class SelectorParser extends Parser {
return AttributeOperator.substring;

default:
scanner.error('Expected "]".', position: start.position);
scanner.error('Expected "]".', position: start);
}
}

Expand Down Expand Up @@ -486,16 +486,12 @@ class SelectorParser extends Parser {
return scanner.scanChar($asterisk)
? UniversalSelector(spanFrom(start), namespace: "*")
: TypeSelector(
QualifiedName(identifier(), namespace: "*"),
spanFrom(start),
);
QualifiedName(identifier(), namespace: "*"), spanFrom(start));
} else if (scanner.scanChar($pipe)) {
return scanner.scanChar($asterisk)
? UniversalSelector(spanFrom(start), namespace: "")
: TypeSelector(
QualifiedName(identifier(), namespace: ""),
spanFrom(start),
);
QualifiedName(identifier(), namespace: ""), spanFrom(start));
}

var nameOrNamespace = identifier();
Expand All @@ -505,9 +501,8 @@ class SelectorParser extends Parser {
return UniversalSelector(spanFrom(start), namespace: nameOrNamespace);
} else {
return TypeSelector(
QualifiedName(identifier(), namespace: nameOrNamespace),
spanFrom(start),
);
QualifiedName(identifier(), namespace: nameOrNamespace),
spanFrom(start));
}
}

Expand Down
Loading
Loading