Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2176)

Unified Diff: sdk/lib/_internal/pub/lib/src/preprocess.dart

Issue 300843007: Run a simple preprocessor on the sources pub loads in barback isolates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: code review Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/pub/lib/src/preprocess.dart
diff --git a/sdk/lib/_internal/pub/lib/src/preprocess.dart b/sdk/lib/_internal/pub/lib/src/preprocess.dart
new file mode 100644
index 0000000000000000000000000000000000000000..827d25635c20cba80f7764c5a7d1c6dca2ed0883
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/preprocess.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2014, 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 pub.preprocess;
+
+import 'package:string_scanner/string_scanner.dart';
+
+import 'version.dart';
+
+/// Runs a simple preprocessor over [input] to remove sections that are
+/// incompatible with the available barback version.
+///
+/// [barbackVersion] is the version of barback that's available, and [sourceUrl]
+/// is a [String] or [Uri] indicating where [input] came from. It's used for
+/// error reporting.
+///
+/// For the most part, the preprocessor leaves text in the source document
+/// alone. However, it handles two types of lines specially. Lines that begin
+/// with `//>` are uncommented by the preprocessor, and lines that begin with
+/// `//#` are operators.
+///
+/// The preprocessor currently supports one top-level operator, "if":
+///
+/// //# if barback >=0.14.1
+/// ...
+/// //# else
+/// ...
+/// //# end
+///
+/// If the current barback version matches the constraint, everything within the
+/// first block is included in the output and everything within the second block
+/// is removed; otherwise, the first block is removed and the second block is
+/// included. The `else` block is optional.
+///
+/// It's important that the preprocessor syntax also be valid Dart code, because
+/// pub loads the source files before preprocessing and runs them against the
+/// version of barback that was compiled into pub. This is why the `//>` syntax
+/// exists: so that code can be hidden from the running pub process but still be
+/// visible to the barback isolate. For example:
+///
+/// //# if barback >= 0.14.1
+/// ClassMirror get aggregateClass => reflectClass(AggregateTransformer);
+/// //# else
+/// //> ClassMirror get aggregateClass => null;
+/// //# end
+String preprocess(String input, Version barbackVersion, sourceUrl) {
+ // Short-circuit if there are no preprocessor directives in the file.
+ if (!input.contains(new RegExp(r"^//[>#]", multiLine: true))) return input;
+ return new _Preprocessor(input, barbackVersion, sourceUrl).run();
+}
+
+/// The preprocessor class.
+class _Preprocessor {
+ /// The scanner over the input string.
+ final StringScanner _scanner;
+
+ /// The version of barback to match against.
+ final Version _barbackVersion;
+
+ /// The buffer to which the output is written.
+ final _buffer = new StringBuffer();
+
+ _Preprocessor(String input, this._barbackVersion, sourceUrl)
+ : _scanner = new StringScanner(input, sourceUrl: sourceUrl);
+
+ /// Run the preprocessor and return the processed output.
+ String run() {
+ while (!_scanner.isDone) {
+ if (_scanner.scan(new RegExp(r"//#\s*"))) {
+ _if();
+ } else {
+ _emitText();
+ }
+ }
+
+ _scanner.expectDone();
+ return _buffer.toString();
+ }
+
+ /// Emit lines of the input document directly until an operator is
+ /// encountered.
+ void _emitText() {
+ while (!_scanner.isDone && !_scanner.matches("//#")) {
+ if (_scanner.scan("//>")) {
+ if (!_scanner.matches("\n")) _scanner.expect(" ");
+ }
+
+ _scanner.scan(new RegExp(r"[^\n]*\n?"));
+ _buffer.write(_scanner.lastMatch[0]);
+ }
+ }
+
+ /// Move through lines of the input document without emitting them until an
+ /// operator is encountered.
+ void _ignoreText() {
+ while (!_scanner.isDone && !_scanner.matches("//#")) {
+ _scanner.scan(new RegExp(r"[^\n]*\n?"));
+ }
+ }
+
+ /// Handle an `if` operator.
+ void _if() {
+ _scanner.expect(new RegExp(r"if\s+"), name: "if statement");
+ _scanner.expect(new RegExp(r"[a-zA-Z0-9_]+"), name: "package name");
+ var package = _scanner.lastMatch[0];
+ if (package != 'barback') _scanner.error('Unknown package "$package".');
+
+ _scanner.scan(new RegExp(r"\s*"));
+ _scanner.expect(new RegExp(r"[^\n]+"), name: "version constraint");
+ var constraint;
+ try {
+ constraint = new VersionConstraint.parse(_scanner.lastMatch[0]);
+ } on FormatException catch (error) {
+ _scanner.error("Invalid version constraint: ${error.message}");
+ }
+ _scanner.expect("\n");
+
+ var allowed = constraint.allows(_barbackVersion);
+ if (allowed) {
+ _emitText();
+ } else {
+ _ignoreText();
+ }
+
+ _scanner.expect("//#");
+ _scanner.scan(new RegExp(r"\s*"));
+ if (_scanner.scan("else")) {
+ _scanner.expect("\n");
+ if (allowed) {
+ _ignoreText();
+ } else {
+ _emitText();
+ }
+ _scanner.expect("//#");
+ _scanner.scan(new RegExp(r"\s*"));
+ }
+
+ _scanner.expect("end");
+ if (!_scanner.isDone) _scanner.expect("\n");
+ }
+}
« no previous file with comments | « sdk/lib/_internal/pub/lib/src/barback/pub_package_provider.dart ('k') | sdk/lib/_internal/pub/test/preprocess_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698